最近要在应用里面使用语音识别功能,老板选择了科大讯飞的技术,小可也就开始看文档啦;
这里只嵌入了语音识别,其他的语法什么的没有研究,有需要的各位看文档呗;
需要的资料 :只识别数字,若不过滤则把LSpeechManager中的onResult方法中的LDataFormat过滤去掉即可
1,首先要在科大讯飞开放平台注册开发者,并注册应用,然后下载SDK;
http://open.voicecloud.cn/index.php/default/index
2,语音识别需要的文件:
(1)Msc.jar
(2)libmsc.so
3,需要的权限 :
- <!-- 网络权限 -->
- <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.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <!-- 手机状态的监听权限 -->
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- public class Lapp extends Application {
- @Override
- public void onCreate() {
- // 应用程序入口处调用,避免手机内存过小,杀死后台进程,造成SpeechUtility对象为null
- // 设置你申请的应用appid
- SpeechUtility.createUtility(Lapp.this, "appid=5486584a");
- super.onCreate();
- }
- }
5,语音识别 (使用该类可以直接调用start()方法进行语音听写识别)
- /**
- * 语音识别管理类
- *
- * @author li'mingqi
- *
- */
- public class LSpeechManager {
- private Context mContext;
- // 语音听写
- private SpeechRecognizer mIat;
- // handler
- private Handler mHandler;
- // 识别结果
- private LSpeechResultListener resultListener;
- // 识别成功
- public static final int SPEECH_SUCCESS = 0;
- // 识别失败
- public static final int SPEECH_FAIL = -1;
- // 开始识别
- public static final int SPEECH_START = 1;
- // 识别出错
- public static final int SPEECH_ERROR = 2;
- /**
- *
- */
- @SuppressLint("HandlerLeak")
- public LSpeechManager(Context context) {
- this.mContext = context;
- // 语音听写部分
- // 创建SpeechRecognizer对象
- mIat = SpeechRecognizer.createRecognizer(this.mContext, null);
- // 设置听写参数
- // 应用领域 --语音识别
- mIat.setParameter(SpeechConstant.DOMAIN, "iat");
- // 语言--中文
- mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
- // mandarin 普通话 cantonese广东话
- mIat.setParameter(SpeechConstant.ACCENT, "mandarin");
- // 客户端引擎选择模式 --云端msc
- mIat.setParameter(SpeechConstant.ENGINE_MODE, "msc");
- // 客户端引擎类型 --云端msc
- mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
- // 数据解码方式 --utf-8
- mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
- // 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- int what = msg.what;
- switch (what) {
- case SPEECH_SUCCESS:// 识别成功
- String result = (String) msg.obj;
- if (null != resultListener) {
- resultListener.onSuccess(result);
- }
- break;
- case SPEECH_FAIL:// 识别失败
- Toast.makeText(mContext, "请将金额数字按普通话讲出", Toast.LENGTH_SHORT)
- .show();
- break;
- case SPEECH_START://开始识别
- if (null != resultListener) {
- resultListener.onStart();
- }
- break;
- case SPEECH_ERROR://识别出错
- if (null != resultListener) {
- String error = (String) msg.obj;
- resultListener.onError(error);
- }
- break;
- }
- }
- };
- }
- public void start() {
- final StringBuilder sb = new StringBuilder();
- // 开始听写
- mIat.startListening(new RecognizerListener() {
- @Override
- public void onVolumeChanged(int arg0) {
- // 音量值变化
- }
- @Override
- public void onResult(RecognizerResult msg, boolean arg1) {
- // 一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
- // 关于解析Json的代码可参见MscDemo中JsonParser类;
- // isLast等于true时会话结束。
- /***
- * 结果--{"sn":1,"ls":false,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[
- * {"w":"两百","sc":0.00}]}]}
- * 结果--{"sn":2,"ls":true,"bg":0,"ed":0,"ws"
- * :[{"bg":0,"cw":[{"w":"。","sc":0.00}]}]}
- */
- try {
- JSONObject mRsult = new JSONObject(msg.getResultString());
- if (!mRsult.getBoolean("ls")) {
- JSONArray data = mRsult.getJSONArray("ws");
- for (int i = 0; i < data.length(); i++) {
- JSONObject w = data.getJSONObject(i);
- JSONArray array = w.getJSONArray("cw");
- for (int k = 0; k < array.length(); k++) {
- JSONObject cwdata = array.getJSONObject(k);
- sb.append(cwdata.getString("w"));
- }
- }
- } else {
- mIat.stopListening();
- String money = LDataFormat.format(sb.toString());
- if ("".equals(money) || null == money
- || "0".equals(money)) {
- Message msgs = mHandler.obtainMessage();
- msgs.what = SPEECH_FAIL;
- mHandler.sendMessage(msgs);
- } else {
- Message msgs = mHandler.obtainMessage();
- msgs.what = SPEECH_SUCCESS;
- msgs.obj = money;
- mHandler.sendMessage(msgs);
- }
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
- // 扩展类回调
- }
- @Override
- public void onError(SpeechError error) {
- // 回话发生错误时回调的函数
- String merror = error.getPlainDescription(true);// 获取错误码描述
- Message msg=mHandler.obtainMessage();
- msg.what=SPEECH_ERROR;
- msg.obj=merror;
- mHandler.sendMessage(msg);
- }
- @Override
- public void onEndOfSpeech() {
- // 结束录音
- }
- @Override
- public void onBeginOfSpeech() {
- // 开始录音
- Message msg=mHandler.obtainMessage();
- msg.what=SPEECH_START;
- mHandler.sendMessage(msg);
- }
- });
- }
- /**识别回调
- * @param resultListener
- * the resultListener to set
- */
- public void setResultListener(LSpeechResultListener resultListener) {
- this.resultListener = resultListener;
- }
- public interface LSpeechResultListener {
- public void onStart();//开始识别
- public void onError(String error);//识别出现错误 ---错误的内容
- public void onSuccess(String result);//识别成功 ---识别结果
- }
- }
6,贴上过滤文字和其他无关的内容的LDateFormat类 (很大一部分是别人写的,谢谢那位大神!)
- /**
- * 数据格式化
- * <ol>
- * 该类主要解决语音输入时携带汉字或者汉字数字混合的字符串情况
- * <li>该类会将除{'分','毛','块','十','百','千','万','亿','一','二','三'...}以外所有的汉字移除并替换格式补位.
- * 即'十'放在十位,'百'放在百位...
- * <li>例如:你好,280元----->280;两百八十元------>280
- * <ol>
- *
- * @author li'mingqi
- * @version 1.0
- */
- public class LDataFormat {
- // 全局数组,存储单位量级
- public static String[] strCHup = { "亿", "万", "千", "百", "十", "元" };
- /***
- * 格式化数据
- *
- * @param source
- * 语音输入的数据
- * @return 返回格式化后的数字字符串
- *
- * li'mingqi 2014-12-11
- *
- **/
- public static String format(String source) {
- // 1,去除不相干的文字信息
- char[] pt = source.toCharArray();
- for (int i = 0; i < pt.length; i++) {
- char k = pt[i];
- if (k == '一' || k == '二' || k == '两' || k == '三' || k == '四'
- || k == '五' || k == '六' || k == '七' || k == '八' || k == '九'
- || k == '十' || k == '百' || k == '千' || k == '万' || k == '亿'
- || k == '0' || k == '1' || k == '2' || k == '3' || k == '4'
- || k == '5' || k == '6' || k == '7' || k == '8' || k == '9') {
- } else {
- source = source.replace(k + "", "");
- }
- }
- // 去除空格间隙
- source.trim();
- // 2,汉字'十','百','千'的转换
- long money = 0;
- // 如果不是数字也就是 一千万这样的汉字 ---则需要转换 如 一百五十万----1500000
- if (source.contains("一") || source.contains("二")
- || source.contains("两") || source.contains("三")
- || source.contains("四") || source.contains("五")
- || source.contains("六") || source.contains("七")
- || source.contains("八") || source.contains("九")
- || source.contains("十") || source.contains("百")
- || source.contains("千") || source.contains("万")
- || source.contains("亿")) {
- money = excuteCharge(source);
- }
- // 数据的来源直接就是阿拉伯数字 如200元---此时元已经去掉,即数字200
- else {
- if (!"".equals(source)) {
- money = Integer.parseInt(source);
- }
- }
- // 3,返回最终格式化结果
- return money + "";
- }
- /***
- * 通过两次递归调用实现分割.
- *
- * @param str
- * @return li'mingqi 2014-12-11
- */
- public static long excuteCharge(String str) {
- // 存储量级单位
- long midNumber = 0;
- // 存储是否可以找到最高量级
- int bre = -1;
- // 找到后根据索引实行字符串分割
- int split = 0;
- // 通过循环查找最高量级
- for (int i = 0; i < strCHup.length; i++) {
- bre = str.indexOf(strCHup[i]);
- if (bre != -1) {
- split = i;
- switch (i) {
- case 0:
- midNumber = 100000000;
- break;
- case 1:
- midNumber = 10000;
- break;
- case 2:
- midNumber = 1000;
- break;
- case 3:
- midNumber = 100;
- break;
- case 4:
- midNumber = 10;
- break;
- case 5:
- midNumber = 1;
- break;
- }
- // 只需要找到最高量级,找到即刻跳出循环.
- break;
- }
- }
- // 如果没有找到量级数.说明该数很小,直接调用add()返回该值.
- if (bre == -1) {
- return add(str);
- }
- // 否则要根据量级进行字符串侵害和返回侵害前部分的值
- else {
- // 如果大型整数,如:十万 等.因为后面不需要再分割
- if (str.length() == bre + 1) {
- // 对于单个量级的值,如:十、百、千、万等。不需要裁减字符串。直接返回量级即可
- if (str.length() == 1) {
- return midNumber;
- } else {
- return add(str.substring(0, str.length() - 1)) * midNumber;
- }
- }
- // 对于只有两位数的.如:十九.直接调用add()返回值即可.不能在此处递归.
- else if (str.length() == bre + 2) {
- return add(str);
- }
- // 其他情况则取值和分割.然后再递归调用.
- else {
- String[] strPart = str.split(strCHup[split]);
- return (add(strPart[0]) * midNumber) + excuteCharge(strPart[1]);
- }
- }
- }
- public static long add(String str) {
- // 存储strCHup里具体汉字的数字值
- long mid = 0;
- // 存储strNumup里具体汉字的数字值
- int number = 0;
- // 存储传入字符串的最高级别单位在strCHup数组里的索引.
- int num = -1;
- for (int i = 0; i < strCHup.length; i++) {
- // 取得量级在字符串中的索引.
- num = str.indexOf(strCHup[i]);
- // 定义char型变量,存储每个汉字.便于后面比较
- char ch = ' ';
- // //
- if (num != -1) {
- switch (i) {
- case 0:
- mid = 100000000;
- break;
- case 1:
- mid = 10000;
- break;
- case 2:
- mid = 1000;
- break;
- case 3:
- mid = 100;
- break;
- case 4:
- mid = 10;
- break;
- case 5:
- mid = 1;
- break;
- }
- // 如果以"十"开关的,直接定义number的值.因为在上面能够找到它的量级.
- if ((str.toCharArray())[0] == '十') {
- number = 1;
- }
- // 否则,取得量级前的数字进行比较,再确定number的值
- else {
- if (0 != num) {
- ch = (str.toCharArray())[num - 1];
- }
- }
- //
- }
- // 循环结束
- //
- // 如果整个字符串就一个字,那么就应该取该值进行比较.而不是再取量级前的数字.
- if (str.length() == 1) {
- ch = (str.toCharArray())[0];
- }
- // 防止几万零几这样的数.
- else if ((str.length() == 2) && ((str.toCharArray())[0] == '零')) {
- ch = (str.toCharArray())[1];
- }
- switch (ch) {
- case '零':
- number = 0;
- break;
- case '一':
- number = 1;
- break;
- case '二':
- number = 2;
- break;
- case '两':
- number = 2;
- break;
- case '三':
- number = 3;
- break;
- case '四':
- number = 4;
- break;
- case '五':
- number = 5;
- break;
- case '六':
- number = 6;
- break;
- case '七':
- number = 7;
- break;
- case '八':
- number = 8;
- break;
- case '九':
- number = 9;
- break;
- }
- // ///
- if (num != -1) {
- break;
- }
- }
- if (num == -1) {
- return number;
- }
- String strLeft = str.substring(num + 1);
- return (number * mid) + add(strLeft);
- }
- }
- public class MainActivity extends Activity {
- /**语音识别管理**/
- LSpeechManager manager;
- /**识别内容输入框**/
- EditText text;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- text = (EditText) findViewById(R.id.editText1);
- manager = new LSpeechManager(this);
- manager.setResultListener(new LSpeechResultListener() {
- @Override
- public void onSuccess(String result) {
- // 识别结束
- text.setText(result);
- }
- @Override
- public void onError(String error) {
- // 识别出现异常
- }
- @Override
- public void onStart() {
- // 识别开始
- }
- });
- }
- public void onClick(View v) {
- int id = v.getId();
- switch (id) {
- case R.id.button1:// 开始识别
- manager.start();
- break;
- }
- }