Android 集成科大讯飞语言SDK(二)

上面一篇文章已经清楚的向大家介绍了Android集成科大讯飞语言SDK的一些准备工作,这篇文章则给大家介绍如何使用下载好的sdk,并提供一个简单的示例。首先看效果:
效果
完整代码已开源至github: https://github.com/UserAndy/testVoice

1.1 添加资源

在上一篇文章中,已经很详细的为大家介绍了下载sdk解压后的目录,这里不再重复,我们将其assets文件夹复制到项目中(app->src->main->assets),assets 文件夹如下图(1)所示,复制到的目录如下图(2)所示:
资源文件
图(1) 资源文件夹
目录文件夹
图(2) 拷贝的目标目录

1.2 添加lib库

使用语言识别功能,就必须使用设备的录用功能,也就免不了使用lib,下载好的sdk也为我们准备好了,只需要拷贝就行,这里我们需要在(app->src->main)文件夹下,新建名为jniLibs的文件夹,并将其sdk下lib目录下的如下文件夹(如图(3)),复制到其目录下:
文件夹
图(3) lib库文件
将Msc.jar 与Sunflower.jar 则添加到 libs文件夹中,添加后的目录如图(4)所示:
添加完成的目录
图(4) 添加完成后的界面

1.3 添加权限

使用语音识别是需要权限的,如录音权限,读取网络状态权限,在 AndroidManifest.xml 文件中添加如下权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--连接网络权限 -->
<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"/>
<!--外存储读权限, -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

添加完成后,我们已经完成了大部分了,童鞋,坚持一下马上就能完成了,继续往下看吧!

1.4 语音集成基类

在这里,通过官方提供的sdk中,提取并简单的封装了一个基类,在使用语音时,只需要继承下面基类即完成语音识别操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
   public class IatBasicActivity extends AppCompatActivity {

public static final String PRIVATE_SETTING="com.iflytek.setting"; //缓存数据的名称
private static final String TAG = "BasicIatActivity";
private EditText mContent; //显示内容
// 语音听写对象
private SpeechRecognizer mIat;
// 语音听写UI
private RecognizerDialog mIatDialog;
// 用HashMap存储听写结果
private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
private SharedPreferences mSharedPreferences;

private Toast mToast;
// 引擎类型
private String mEngineType = SpeechConstant.TYPE_CLOUD;

int ret = 0; // 函数调用返回值


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SpeechUtility.createUtility(this, SpeechConstant.APPID + "=5763509a");
Log.d(TAG, "onCreate--->");
initIat();
//初始化组件 后期修改为,程序一进入的时候进行初始化
mToast = Toast.makeText(IatBasicActivity.this,"",Toast.LENGTH_SHORT);
}

/**
* 显示toast
* @param content 待显示的内容
*/
public void showTip(String content){
mToast.setText(content);
mToast.show();
}

/**
* 初始化 EditText 在需要调用语音接口中的类的初始化方法中调用该方法
*
* @param mContent
*/
public void initIatData(EditText mContent) {
this.mContent = mContent;
}

/**
* 初始化语音识别中的对象
*/
private void initIat() {
// 使用SpeechRecognizer对象,可根据回调消息自定义界面;
mIat = SpeechRecognizer.createRecognizer(this, mInitListener);
// 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
// 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源
mIatDialog = new RecognizerDialog(this, mInitListener);
mSharedPreferences = getSharedPreferences(PRIVATE_SETTING,
Activity.MODE_PRIVATE);

}

/**
* 初始化监听器
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失败,错误码:" + code);
}
}
};

/**
* 听写UI监听器
*/
private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
public void onResult(RecognizerResult results, boolean isLast) {
Log.d(TAG, results.getResultString());
printResult(results, mContent);
Log.d(TAG, results.getResultString());
}

/**
* 识别回调错误.
*/
public void onError(SpeechError error) {
showTip(error.getPlainDescription(true));
}
};
/**
* 听写监听器。
*/
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) {
Log.d(TAG, results.getResultString());
printResult(results, mContent);
Log.d(TAG, results.getResultString());
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_SESSION_ID);
// Log.d(TAG, "session id =" + sid);
// }
}
};

/**
* 参数设置
* @param
* @return
*/
public void setParam() {
// 清空参数
mIat.setParameter(SpeechConstant.PARAMS, null);
// 设置听写引擎
mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
// 设置返回结果格式
mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
String lag = mSharedPreferences.getString("iat_language_preference",
"mandarin");
if (lag.equals("en_us")) {
// 设置语言
mIat.setParameter(SpeechConstant.LANGUAGE, "en_us");
} else {
// 设置语言
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权限
// 注:AUDIO_FORMAT参数语记需要更新版本才能生效
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
}


/**
* 触发点击事件时的方法
*/
public void clickMethod() {
mContent.setText(null);// 清空显示内容
mIatResults.clear();
// 设置参数
setParam();
boolean isShowDialog = mSharedPreferences.getBoolean(getString(R.string.pref_key_iat_show), true);
if (isShowDialog) {
// 显示听写对话框
mIatDialog.setListener(mRecognizerDialogListener);
mIatDialog.show();
showTip(getString(R.string.text_begin));
} else {
// 不显示听写对话框
ret = mIat.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
Log.d(TAG, "听写失败,错误码:" + ret);
} else {
showTip(getString(R.string.text_begin));
}
}
}

/**
* 显示结果,并赋值到EditText文本框中
*
* @param results
* @param editText
*/
private void printResult(RecognizerResult results, EditText editText) {
String text = JsonParser.parseIatResult(results.getResultString());

String sn = null;
// 读取json结果中的sn字段
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 content = resultBuffer.toString();
Log.d(TAG, content);
content = content.replace("。", "".trim()); //去掉最后面的 。
editText.setText(content);
editText.setSelection(content.length());
}
}

在使用时,在调用时,仅需要四个步骤:
① 修改appid

1
SpeechUtility.createUtility(this, SpeechConstant.APPID + "=5763509a");

将5763509a替换成您申请的appid.
② 继承 IatBasicActivity 类。
③ 在子类中 onCreate()方法 中调用:父类的 initIatData(EditText text); 其中 text是需要赋值的文本框。
④ 在触发事件中调用 调用 父类的 clickMethod()方法。

1.6 调用示例

这是一个简单的调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class MainActivity extends IatBasicActivity implements View.OnClickListener{

private EditText mContent;
private Button mBtnVoice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//5763509a
initView();
}

/**
* 初始化视图
*/
private void initView(){
mContent = (EditText)findViewById(R.id.et_content);
mBtnVoice =(Button)findViewById(R.id.btn_voice);
mBtnVoice.setOnClickListener(this);
//调用父类方法
initIatData(mContent);
}

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_voice:
//调用父类方法
clickMethod();
break;
}
}
}

1.7 小结

以上是集成科大讯飞语音识别的主要细节,省略了部分资源文件,完整的demo已开源至github,有兴趣的童鞋,可以直接从github下载,