最近在做毕设项目中,要用到一个语音识别的功能,主要目的是把用户说的话转换成文字,然后再做其他处理。找了多个语音识别的第三方SDK,比如百度语音识别、微信语音识别、科大讯飞语音识别,发现科大讯飞的比较好用。做了一个Demo程序,有详细的注释,在这里整理一下。
(一)准备工作
0、创建一个空的Android项目,比如项目名叫:SpeechRecognitionDemoJYJ。
1、首先要在科大讯飞开放平台上注册,或者用QQ等第三方登录也行。
2、点击网站首页右上角的“控制台”,进入控制台。
3、按照说明创建一个应用,该应用名就叫SpeechRecognitionDemoJYJ,创建成功后会有一个AppID,记下来,编程的时候要用到。
4、点击SpeechRecognitionDemoJYJ后面的“开通服务”按钮,开通服务—>语音听写,进入语音听写—>下载当前应用对应的SDK。
libs目录下的Msc.jar和armeabi复制到Android工程的libs目录(如果工程无libs目录,请自行创建)中,并且因为还要用到语音听写Dialog,所以还要把SDK包中assets目录下的iflytek文件夹复制到工程的assets目录下,如下图所示。还要注意,每个不同的应用都要申请不同的AppID,并且要分别下载不同AppID对应的SDK,否则会出错。
6、其他更详细的说明和资料可以参看讯飞开放平台的资料库
(二)开发
Demo实现的功能很简单,就是点击一个按钮,弹出语音识别Dialog窗口,说话,说完了点击Dialog窗口后会把自动识别的文字结果显示在下方的EditText中。服务器返回的语音听写的结果是Json格式数据,最后还要对Json数据进行解析(具体解析方法参看我的这篇文章:用GSON解析Json格式数据),解析出语音字符串。
1、XML代码:
界面中有一个按钮,一个TextView和一个EditText,EditText用于显示语音识别的结果。
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical" >
5
6 <Button
7 android:id="@+id/listen_btn"
8 android:layout_width="match_parent"
9 android:layout_height="wrap_content"
10 android:text="开始说话" />
11
12 <TextView
13 android:id="@+id/task_tv"
14 android:layout_width="match_parent"
15 android:layout_height="wrap_content"
16 android:layout_margin="20dp"
17 android:text="日程安排:" />
18
19 <EditText
20 android:id="@+id/content_et"
21 android:layout_width="match_parent"
22 android:layout_height="wrap_content"
23 android:background="@android:drawable/editbox_dropdown_light_frame"
24 android:cursorVisible="true"
25 android:enabled="true"
26 android:gravity="top"
27 android:visibility="visible" />
28
29 </LinearLayout>
2、MainActivity
1 import java.lang.reflect.Type;
2 import java.util.List;
3
4 import com.example.speechrecognition.DictationResult;
5 import com.google.gson.Gson;
6 import com.google.gson.reflect.TypeToken;
7 import com.iflytek.cloud.RecognizerListener;
8 import com.iflytek.cloud.RecognizerResult;
9 import com.iflytek.cloud.SpeechConstant;
10 import com.iflytek.cloud.SpeechError;
11 import com.iflytek.cloud.SpeechRecognizer;
12 import com.iflytek.cloud.SpeechUtility;
13 import com.iflytek.cloud.ui.RecognizerDialog;
14 import com.iflytek.cloud.ui.RecognizerDialogListener;
15
16 import android.app.Activity;
17 import android.content.Context;
18 import android.os.Bundle;
19 import android.os.Handler;
20 import android.os.Message;
21 import android.util.Log;
22 import android.view.Menu;
23 import android.view.MenuItem;
24 import android.view.View;
25 import android.view.View.OnClickListener;
26 import android.view.inputmethod.InputMethodManager;
27 import android.widget.Button;
28 import android.widget.EditText;
29 import android.widget.TextView;
30
31 public class MainActivity extends Activity implements OnClickListener {
32 private static String APPID = "569e39a1";
33
34 private Button listenBtn;
35 private EditText contentEt;
36
37 // 听写结果字符串(多个Json的列表字符串)
38 private String dictationResultStr = "[";
39
40 @Override
41 protected void onCreate(Bundle savedInstanceState) {
42 super.onCreate(savedInstanceState);
43 setContentView(R.layout.activity_main);
44
45 listenBtn = (Button) findViewById(R.id.listen_btn);
46 contentEt = (EditText) findViewById(R.id.content_et);
47
48 listenBtn.setOnClickListener(this);
49
50 }
51
52 @Override
53 public void onClick(View v) {
54 switch (v.getId()) {
55 case R.id.listen_btn:
56
57 dictationResultStr = "[";
58 // 语音配置对象初始化
59 SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID
60 + "=" + APPID);
61
62 // 1.创建SpeechRecognizer对象,第2个参数:本地听写时传InitListener
63 SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(
64 MainActivity.this, null);
65 // 交互动画
66 RecognizerDialog iatDialog = new RecognizerDialog(
67 MainActivity.this, null);
68 // 2.设置听写参数,详见《科大讯飞MSC API手册(Android)》SpeechConstant类
69 mIat.setParameter(SpeechConstant.DOMAIN, "iat"); // domain:域名
70 mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
71 mIat.setParameter(SpeechConstant.ACCENT, "mandarin"); // mandarin:普通话
72
73 //3.开始听写
74 iatDialog.setListener(new RecognizerDialogListener() {
75
76 @Override
77 public void onResult(RecognizerResult results, boolean isLast) {
78 // TODO 自动生成的方法存根
79 // Log.d("Result", results.getResultString());
80 // contentTv.setText(results.getResultString());
81 if (!isLast) {
82 dictationResultStr += results.getResultString() + ",";
83 } else {
84 dictationResultStr += results.getResultString() + "]";
85 }
86 if (isLast) {
87 // 解析Json列表字符串
88 Gson gson = new Gson();
89 List<DictationResult> dictationResultList = gson
90 .fromJson(dictationResultStr,
91 new TypeToken<List<DictationResult>>() {
92 }.getType());
93 String finalResult = "";
94 for (int i = 0; i < dictationResultList.size() - 1; i++) {
95 finalResult += dictationResultList.get(i)
96 .toString();
97 }
98 contentEt.setText(finalResult);
99
100 //获取焦点
101 contentEt.requestFocus();
102
103 //将光标定位到文字最后,以便修改
104 contentEt.setSelection(finalResult.length());
105
106 Log.d("From reall phone", finalResult);
107 }
108 }
109
110 @Override
111 public void onError(SpeechError error) {
112 // TODO 自动生成的方法存根
113 error.getPlainDescription(true);
114 }
115 });
116
117 // 开始听写
118 iatDialog.show();
119
120 break;
121 default:
122 break;
123 }
124 }
125 }
3、自定义的com.example.speechrecognition.DictationResult类的代码:
1 import java.util.List;
2
3 /**
4 * 解析语音听写返回结果Json格式字符串的模板类(多重嵌套Json)
5 *
6 * 语音识别结果Json数据格式(单条数据):
7 * {"sn":1,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"w":"今天","sc":0}]},
8 * {"bg":0,"cw":{"w":"的","sc":0}]},{"bg":0,"cw":[{"w":"天气","sc":0}]},
9 * {"bg":0,"cw":[{"w":"怎么样","sc":0}]},{"bg":0,"cw":[{"w":"。","sc":0}]}]}
10 */
11 public class DictationResult {
12 private String sn;
13 private String ls;
14 private String bg;
15 private String ed;
16
17 private List<Words> ws;
18
19 public static class Words {
20 private String bg;
21 private List<Cw> cw;
22
23 public static class Cw {
24 private String w;
25 private String sc;
26
27 public String getW() {
28 return w;
29 }
30
31 public void setW(String w) {
32 this.w = w;
33 }
34
35 public String getSc() {
36 return sc;
37 }
38
39 public void setSc(String sc) {
40 this.sc = sc;
41 }
42
43 @Override
44 public String toString() {
45 return w;
46 }
47 }
48
49 public String getBg() {
50 return bg;
51 }
52
53 public void setBg(String bg) {
54 this.bg = bg;
55 }
56
57 public List<Cw> getCw() {
58 return cw;
59 }
60
61 public void setCw(List<Cw> cw) {
62 this.cw = cw;
63 }
64
65 @Override
66 public String toString() {
67 String result = "";
68 for (Cw cwTmp : cw) {
69 result += cwTmp.toString();
70 }
71 return result;
72 }
73 }
74
75 public String getSn() {
76 return sn;
77 }
78
79 public void setSn(String sn) {
80 this.sn = sn;
81 }
82
83 public String getLs() {
84 return ls;
85 }
86
87 public void setLs(String ls) {
88 this.ls = ls;
89 }
90
91 public String getBg() {
92 return bg;
93 }
94
95 public void setBg(String bg) {
96 this.bg = bg;
97 }
98
99 public String getEd() {
100 return ed;
101 }
102
103 public void setEd(String ed) {
104 this.ed = ed;
105 }
106
107 public List<Words> getWs() {
108 return ws;
109 }
110
111 public void setWs(List<Words> ws) {
112 this.ws = ws;
113 }
114
115 @Override
116 public String toString() {
117 String result = "";
118 for (Words wsTmp : ws) {
119 result += wsTmp.toString();
120 }
121 return result;
122 }
123 }
4、AndroidManifest.xml中申请权限:
1 <!-- 连接网络权限,用于执行云端语音能力 -->
2 <uses-permission android:name="android.permission.INTERNET"/>
3 <!-- 获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
4 <uses-permission android:name="android.permission.RECORD_AUDIO"/>
5 <!--读取网络信息状态 -->
6 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
7 <!--获取当前wifi状态 -->
8 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
9 <!--允许程序改变网络连接状态 -->
10 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
11 <!--读取手机信息权限 -->
12 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
13 <!--读取联系人权限,上传联系人需要用到此权限 -->
14 <uses-permission android:name="android.permission.READ_CONTACTS"/>
5、测试:模拟器无法打开录音机,是不能在上面测试的,要用真机测试。测试结果如下图: