Android开发集成科大讯飞语音识别+语音合成功能

转载一篇:

(本Demo的开发环境为Android Studio)。


一、语音识别


1.下载SDK(地址:http://www.xfyun.cn/sdk/dispatcher),选择语音听写SDK(如下图) ,下载前会让你先创建应用,创建应用后会得到一个appid。然后点“立即开通”去开通“语音识别”功能,之后就会跳出“SDK下载”的页面,然后就可以下载了(未注册账号的要先注册一个账号)。




2.将下载好的SDK中 libs 目录下的 Msc.jar包引入到工程中(参见http://blog.csdn.net/highboys/article/details/51549679,此外,因为本Demo中会用到json的东西,所以还得自己去网上下一个Gson的jar包,一并引进去)。之后在main目录下新建一个jniLibs目录,将 SDK中 libs 目录下的armeabi 拷进去,如下图所示(第④个先不用管): 



3.科大讯飞为我们提供了一套语音听写时的UI,即听写的时候会有一个动画效果(如下图),这个时候我们需要 先将 SDK 资源包 assets 路径下的资源文件拷贝至 Android 工程asstes 目录下(没有的话自己新建),参照第2步图的④。



4.接下来就是代码的实现了。首先在Manifest中添加一下权限

[html]  view plain  copy
  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.     <!--SD卡读写的权限(如果需要保存音频文件到本地的话)-->  
  15.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  16.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  17.     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  


其次是java代码(逻辑上是点击了某个Button之后,才执行下面的代码)。

[java]  view plain  copy
  1.     //有动画效果  
  2.     private RecognizerDialog iatDialog;  
  3.   
  4. // ①语音配置对象初始化  
  5.                 SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID + "=578f1af7");//将这里的578f1af7替换成自己申请得到的8位appid  
  6.   
  7.                 // ②初始化有交互动画的语音识别器  
  8.                 iatDialog = new RecognizerDialog(MainActivity.this, mInitListener);  
  9.      //③设置监听,实现听写结果的回调  
  10.                 iatDialog.setListener(new RecognizerDialogListener() {  
  11.                     String resultJson = "[";//放置在外边做类的变量则报错,会造成json格式不对(?)  
  12.   
  13.                     @Override  
  14.                     public void onResult(RecognizerResult recognizerResult, boolean isLast) {  
  15.                         System.out.println("-----------------   onResult   -----------------");  
  16.                         if (!isLast) {  
  17.                             resultJson += recognizerResult.getResultString() + ",";  
  18.                         } else {  
  19.                             resultJson += recognizerResult.getResultString() + "]";  
  20.                         }  
  21.   
  22.                         if (isLast) {  
  23.                             //解析语音识别后返回的json格式的结果  
  24.                             Gson gson = new Gson();  
  25.                             List<DictationResult> resultList = gson.fromJson(resultJson,  
  26.                                     new TypeToken<List<DictationResult>>() {  
  27.                                     }.getType());  
  28.                             String result = "";  
  29.                             for (int i = 0; i < resultList.size() - 1; i++) {  
  30.                                 result += resultList.get(i).toString();  
  31.                             }  
  32.                             etText.setText(result);  
  33.                             //获取焦点  
  34.                             etText.requestFocus();  
  35.                             //将光标定位到文字最后,以便修改  
  36.                             etText.setSelection(result.length());  
  37.                         }  
  38.                     }  
  39.   
  40.                     @Override  
  41.                     public void onError(SpeechError speechError) {  
  42.                         //自动生成的方法存根  
  43.                         speechError.getPlainDescription(true);  
  44.                     }  
  45.                 });  
  46.                 //开始听写,需将sdk中的assets文件下的文件夹拷入项目的assets文件夹下(没有的话自己新建)  
  47.                 iatDialog.show();  

其中的mInitListener定义如下:

[java]  view plain  copy
  1. public static final String TAG = "MainActivity";  
  2. private InitListener mInitListener = new InitListener() {  
  3.     @Override  
  4.     public void onInit(int code) {  
  5.         Log.d(TAG, "SpeechRecognizer init() code = " + code);  
  6.         if (code != ErrorCode.SUCCESS) {  
  7.             Toast.makeText(MainActivity.this"初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();  
  8.         }  
  9.     }  
  10. };  

上面的代码用到了一个DictationResult类(一个用来接收转换 语音听写结果的类),需要自己新建,定义如下

[java]  view plain  copy
  1. /** 
  2.  * 解析 语音听写返回结果Json格式字符串 的模板类(多重嵌套Json) 
  3.  * 
  4.  * 语音识别结果Json数据格式(单条数据): 
  5.  * {"sn":1,"ls":true,"bg":0,"ed":0,"ws":[ 
  6.  * {"bg":0,"cw":[{"w":"今天","sc":0}]}, 
  7.  * {"bg":0,"cw":[{"w":"的","sc":0}]}, 
  8.  * {"bg":0,"cw":[{"w":"天气","sc":0}]}, 
  9.  * {"bg":0,"cw":[{"w":"怎么样","sc":0}]}, 
  10.  * {"bg":0,"cw":[{"w":"。","sc":0}]} 
  11.  * ]} 
  12.  * 
  13.  * sn  number :第几句 
  14.  * ls   boolean: 是否最后一句 
  15.  * bg  number :开始 
  16.  * ed  number :结束 
  17.  * ws  array :词 
  18.  * cw   array :中文分词 
  19.  * w  string :单字 
  20.  * sc  number :分数 
  21.  */  
  22. public class DictationResult {  
  23.     private String sn;  
  24.     private String ls;  
  25.     private String bg;  
  26.     private String ed;  
  27.   
  28.     private List<Words> ws;  
  29.   
  30.     public static class Words {  
  31.         private String bg;  
  32.         private List<Cw> cw;  
  33.   
  34.         public static class Cw {  
  35.             private String w;  
  36.             private String sc;  
  37.   
  38.             public String getW() {  
  39.                 return w;  
  40.             }  
  41.   
  42.             public void setW(String w) {  
  43.                 this.w = w;  
  44.             }  
  45.   
  46.             public String getSc() {  
  47.                 return sc;  
  48.             }  
  49.   
  50.             public void setSc(String sc) {  
  51.                 this.sc = sc;  
  52.             }  
  53.   
  54.             @Override  
  55.             public String toString() {  
  56.                 return w;  
  57.             }  
  58.         }  
  59.   
  60.         public String getBg() {  
  61.             return bg;  
  62.         }  
  63.   
  64.         public void setBg(String bg) {  
  65.             this.bg = bg;  
  66.         }  
  67.   
  68.         public List<Cw> getCw() {  
  69.             return cw;  
  70.         }  
  71.   
  72.         public void setCw(List<Cw> cw) {  
  73.             this.cw = cw;  
  74.         }  
  75.   
  76.         @Override  
  77.         public String toString() {  
  78.             String result = "";  
  79.             for (Cw cwTmp : cw) {  
  80.                 result += cwTmp.toString();  
  81.             }  
  82.             return result;  
  83.         }  
  84.     }  
  85.   
  86.     public String getSn() {  
  87.         return sn;  
  88.     }  
  89.   
  90.     public void setSn(String sn) {  
  91.         this.sn = sn;  
  92.     }  
  93.   
  94.     public String getLs() {  
  95.         return ls;  
  96.     }  
  97.   
  98.     public void setLs(String ls) {  
  99.         this.ls = ls;  
  100.     }  
  101.   
  102.     public String getBg() {  
  103.         return bg;  
  104.     }  
  105.   
  106.     public void setBg(String bg) {  
  107.         this.bg = bg;  
  108.     }  
  109.   
  110.     public String getEd() {  
  111.         return ed;  
  112.     }  
  113.   
  114.     public void setEd(String ed) {  
  115.         this.ed = ed;  
  116.     }  
  117.   
  118.     public List<Words> getWs() {  
  119.         return ws;  
  120.     }  
  121.   
  122.     public void setWs(List<Words> ws) {  
  123.         this.ws = ws;  
  124.     }  
  125.   
  126.     @Override  
  127.     public String toString() {  
  128.         String result = "";  
  129.         for (Words wsTmp : ws) {  
  130.             result += wsTmp.toString();  
  131.         }  
  132.         return result;  
  133.     }  
  134. }  

如此,便可实现语音听写了。这个过程可能会遇到各种各样的问题,具体错误码参见  http://www.xfyun.cn/doccenter/faq


5.说完了有动画效果的,下面就来说说没有动画效果的(也比较简单)。

[java]  view plain  copy
  1. //1.创建SpeechRecognizer对象,第二个参数:本地识别时传InitListener  
  2.     SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(context, null);  
  3.     //2.设置听写参数,详见SDK中《MSC Reference Manual》文件夹下的SpeechConstant类  
  4.     mIat.setParameter(SpeechConstant.DOMAIN,"iat");  
  5.     mIat.setParameter(SpeechConstant.LANGUAGE,"zh_cn");  
  6.     mIat.setParameter(SpeechConstant.ACCENT,"mandarin ");  
  7.   
  8.       //保存音频文件到本地(有需要的话)   仅支持pcm和wav,且需要自行添加读写SD卡权限  
  9.     mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/mIat.wav");  
  10.     // 3.开始听写  
  11.     mIat.startListening(mRecoListener);  
  12.     //听写监听器  
  13.     private RecognizerListener mRecoListener = new RecognizerListener() {  
  14.         //听写结果回调接口(返回Json格式结果,用户可参见附录13.1);  
  15.         // 一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;  
  16.         // 关于解析Json的代码可参见Demo中JsonParser类;  
  17.         // isLast等于true时会话结束。  
  18.         public void onResult(RecognizerResult results, boolean isLast) {  
  19.             Log.d(TAG, "result:" + results.getResultString());  
  20.         }  
  21.   
  22.         //会话发生错误回调接口  
  23.         public void onError(SpeechError error) {  
  24.             //打印错误码描述  
  25.             Log.d(TAG, "error:" + error.getPlainDescription(true))  
  26.         }  
  27.   
  28.         //开始录音  
  29.         public void onBeginOfSpeech() {  
  30.         }  
  31.   
  32.         //    volume音量值0~30,data音频数据  
  33.         public void onVolumeChanged(int volume, byte[] data) {  
  34.         }  
  35.   
  36.         //结束录音  
  37.         public void onEndOfSpeech() {  
  38.         }  
  39.   
  40.         //扩展用接口  
  41.         public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {  
  42.         }  
  43.     };  

可以看到上面的onResult回调方法跟有动画效果时的onResult回调方法是一样的,所以主要的处理还是在这个方法中,将有动画的那个onResult回调中的代码拷过来就行了。如此,简单的语音听写功能就实现了。


二、语音合成


1.语音合成也需要创建语音配置对象:

[java]  view plain  copy
  1. SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID + "=578f1af7");  


2.创建用于语音合成的对象并设置参数,进行语音合成

[java]  view plain  copy
  1.         //1.创建SpeechSynthesizer对象, 第二个参数:本地合成时传InitListener  
  2.         SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(MainActivity.thisnull);  
  3.   
  4.         /** 
  5.          2.合成参数设置,详见《科大讯飞MSC API手册(Android)》SpeechSynthesizer 类 
  6.          * 
  7.          */  
  8.   
  9.         // 清空参数  
  10.         mTts.setParameter(SpeechConstant.PARAMS, null);  
  11.   
  12.         mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置云端  
  13.         mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");//设置发音人  
  14.         mTts.setParameter(SpeechConstant.SPEED, "50");//设置语速  
  15.         //设置合成音调  
  16.         mTts.setParameter(SpeechConstant.PITCH, "50");  
  17.         mTts.setParameter(SpeechConstant.VOLUME, "80");//设置音量,范围0~100  
  18.         mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");  
  19.         // 设置播放合成音频打断音乐播放,默认为true  
  20.         mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");  
  21.   
  22.         // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限  
  23.         // 注:AUDIO_FORMAT参数语记需要更新版本才能生效  
  24. //        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");  
  25. //        boolean isSuccess = mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts2.wav");  
  26. //        Toast.makeText(MainActivity.this, "语音合成 保存音频到本地:\n" + isSuccess, Toast.LENGTH_LONG).show();  
  27.         //3.开始合成  
  28.         int code = mTts.startSpeaking("在这里放置需要进行合成的文本", mSynListener);  
  29.   
  30.         if (code != ErrorCode.SUCCESS) {  
  31.             if (code == ErrorCode.ERROR_COMPONENT_NOT_INSTALLED) {  
  32.                 //上面的语音配置对象为初始化时:  
  33.                 Toast.makeText(MainActivity.this"语音组件未安装", Toast.LENGTH_LONG).show();  
  34.             } else {  
  35.                 Toast.makeText(MainActivity.this"语音合成失败,错误码: " + code, Toast.LENGTH_LONG).show();  
  36.             }  
  37.         }  
  38.   
  39.       

  合成时需要一个SynthesizerListener类型的合成监听器作参数,定义如下


[java]  view plain  copy
  1. //合成监听器  
  2.     private SynthesizerListener mSynListener = new SynthesizerListener() {  
  3.         //会话结束回调接口,没有错误时,error为null  
  4.         public void onCompleted(SpeechError error) {  
  5.         }  
  6.   
  7.         //缓冲进度回调  
  8.         //percent为缓冲进度0~100,beginPos为缓冲音频在文本中开始位置,endPos表示缓冲音频在文本中结束位置,info为附加信息。  
  9.         public void onBufferProgress(int percent, int beginPos, int endPos, String info) {  
  10.         }  
  11.   
  12.         //开始播放  
  13.         public void onSpeakBegin() {  
  14.         }  
  15.   
  16.         //暂停播放  
  17.         public void onSpeakPaused() {  
  18.         }  
  19.   
  20.         //播放进度回调  
  21.         //percent为播放进度0~100,beginPos为播放音频在文本中开始位置,endPos表示播放音频在文本中结束位置.  
  22.         public void onSpeakProgress(int percent, int beginPos, int endPos) {  
  23.         }  
  24.   
  25.         //恢复播放回调接口  
  26.         public void onSpeakResumed() {  
  27.         }  
  28.   
  29.         //会话事件回调接口  
  30.         public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {  
  31.         }  
  32.     };  


本文参照SDK中doc文件夹下的 MSC Develop Manual for Android.pdf文件完成,里边写得很详细。也可参见  http://www.xfyun.cn/doccenter/awd  。

常见问题  http://www.xfyun.cn/doccenter/faq


Demo下载地址:http://download.csdn.net/detail/highboys/9622426

本文转载出处:http://blog.csdn.net/highboys/article/details/52145038