高德地图官方导航部分Demo使用Android sdk 24编译,执行会崩溃。经过和高德工程师的交涉得知,地图中使用了科大讯飞的语音模块,崩溃的就是语音部分。探究一下科大讯飞语音识别,在此记录一下成长点滴!
这里使用的是科大讯飞
科大讯飞API提供的功能
-
语音合成
将一段文字转换为成语音,可根据需要合成出不同音色、语速和语调的声音,让机器像人一样开口说话。
-
语音听写
将一段语音转换成文本,把语音中包含文字信息提取出来,并可以优先识别用户手机特有的联系人和个性化数据。
-
语法识别
判断用户所说的内容是否与预定义的语法相符合, 主要用于识别用户是否下达某项指令,使用语法识别前,需要先定义语法。
-
语义理解
在语音听写基础上,分析理解用户的说话意图,返回结构化的指令信息。开发者可在语义开放平台定义专属的问答格式。
-
语音评测
通过智能语音技术自动对发音水平进行评价,给出用户综合得分和发音信息。
-
声纹密码
据语音波形反映说话人生理和行为特征的语音参数,自动识别说话人身份,声纹识别所提供的安全性可与其他生物识别技术(指纹、掌形和虹膜)相媲美。
-
人脸识别
基于人的脸部特征信息进行身份识别的一种生物识别技术,可以自动在图像中检测和跟踪人脸,进而对检测到的人脸进行检测和验证。系统同时支持人脸关键点检出、视频流人脸检测等功能,识别率高达 99%。
由于时间和能力限制,这里仅仅对语音听写&&语音合成中的云服务部分进行简单探究。
环境搭建
到讯飞官网,申请一个开发者账号,创建一个应用,下载相应的sdk,添加相关的jar和so文件。
1.在Application中完成讯飞模块的初始化
<code class="hljs java has-numbering"> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>() { <span class="hljs-keyword">super</span>.onCreate(); <span class="hljs-comment">// 将“12345678”替换成您申请的 APPID</span> <span class="hljs-comment">// 请勿在“ =” 与 appid 之间添加任务空字符或者转义符</span> SpeechUtility.createUtility(context, SpeechConstant.APPID +<span class="hljs-string">"=12345678"</span>); SpeechUtility.createUtility(<span class="hljs-keyword">this</span>, SpeechConstant.APPID +<span class="hljs-string">"=12345678"</span>); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
2.添加相应的权限
<code class="hljs xml has-numbering"> <span class="hljs-comment"><!--连接网络权限,用于执行云端语音能力 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.INTERNET"</span> /></span> <span class="hljs-comment"><!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.RECORD_AUDIO"</span> /></span> <span class="hljs-comment"><!--读取网络信息状态 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.ACCESS_NETWORK_STATE"</span> /></span> <span class="hljs-comment"><!--获取当前wifi状态 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.ACCESS_WIFI_STATE"</span> /></span> <span class="hljs-comment"><!--允许程序改变网络连接状态 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.CHANGE_NETWORK_STATE"</span> /></span> <span class="hljs-comment"><!--读取手机信息权限 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.READ_PHONE_STATE"</span> /></span> <span class="hljs-comment"><!--读取联系人权限,上传联系人需要用到此权限 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.READ_CONTACTS"</span> /></span> <span class="hljs-comment"><!--外存储写权限, 构建语法需要用到此权限 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.WRITE_EXTERNAL_STORAGE"</span> /></span> <span class="hljs-comment"><!--外存储读权限,构建语法需要用到此权限 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.READ_EXTERNAL_STORAGE"</span> /></span> <span class="hljs-comment"><!--配置权限,用来记录应用配置信息 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.WRITE_SETTINGS"</span> /></span> <span class="hljs-comment"><!--摄相头权限, 拍照需要用到 --></span> <span class="hljs-tag"><<span class="hljs-title">uses-permission</span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"android.permission.CAMERA"</span> /></span> </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul>
语音合成
就是将文本读出来
使用的布局文件如下:
<code class="hljs xml has-numbering"><span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span> <span class="hljs-comment"><!--activity_text2speech.xml--></span> <span class="hljs-tag"><<span class="hljs-title">LinearLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:focusable</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:focusableInTouchMode</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"center_horizontal"</span> <span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"vertical"</span> <span class="hljs-attribute">android:paddingLeft</span>=<span class="hljs-value">"10dp"</span> <span class="hljs-attribute">android:paddingRight</span>=<span class="hljs-value">"10dp"</span>></span> <span class="hljs-tag"><<span class="hljs-title">TextView </span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_centerInParent</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"讯飞合成示例"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"30sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">EditText </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/tts_text"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"top|left"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"科大讯飞作为中国最大的智能语音技术提供商,在智能语音技术领域有着长期的研究积累,并在中文语音合成、语音识别、 口语评测等多项技术上拥有国际领先的成果。科大讯飞是我国唯一以语音技术为产业化方向的“国家863计划成果产业化基地”…"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/tts_play"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"开始合成"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span> </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li></ul>
Java代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.iflytek.voicedemo; <span class="hljs-keyword">import</span> android.Manifest; <span class="hljs-keyword">import</span> android.annotation.SuppressLint; <span class="hljs-keyword">import</span> android.app.Activity; <span class="hljs-keyword">import</span> android.os.Bundle; <span class="hljs-keyword">import</span> android.os.Environment; <span class="hljs-keyword">import</span> android.support.v4.app.ActivityCompat; <span class="hljs-keyword">import</span> android.view.View; <span class="hljs-keyword">import</span> android.view.View.OnClickListener; <span class="hljs-keyword">import</span> android.view.Window; <span class="hljs-keyword">import</span> android.widget.EditText; <span class="hljs-keyword">import</span> android.widget.Toast; <span class="hljs-keyword">import</span> com.iflytek.cloud.ErrorCode; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechConstant; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechError; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechSynthesizer; <span class="hljs-keyword">import</span> com.iflytek.cloud.SynthesizerListener; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Text2SpeechActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OnClickListener</span> {</span> <span class="hljs-comment">// 语音合成对象</span> <span class="hljs-keyword">private</span> SpeechSynthesizer mTts; <span class="hljs-keyword">private</span> Toast mToast; <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"ShowToast"</span>) <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_text2speech); findViewById(R.id.tts_play).setOnClickListener(<span class="hljs-keyword">this</span>); <span class="hljs-comment">// 初始化合成对象</span> mTts = SpeechSynthesizer.createSynthesizer(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">null</span>); mToast = Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">""</span>, Toast.LENGTH_SHORT); applyPermission(); } <span class="hljs-comment">//获取权限,将语音保存到sd卡</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">applyPermission</span>() { ActivityCompat.requestPermissions(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">new</span> String[]{ Manifest.permission.READ_EXTERNAL_STORAGE }, <span class="hljs-number">12</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View view) { <span class="hljs-keyword">switch</span> (view.getId()) { <span class="hljs-comment">// 开始合成</span> <span class="hljs-comment">// 收到onCompleted 回调时,合成结束、生成合成音频</span> <span class="hljs-comment">// 合成的音频格式:只支持pcm格式</span> <span class="hljs-keyword">case</span> R.id.tts_play: { String text = ((EditText) findViewById(R.id.tts_text)).getText().toString(); <span class="hljs-comment">// 设置参数</span> setParam(); <span class="hljs-keyword">int</span> code = mTts.startSpeaking(text, mTtsListener); <span class="hljs-comment">// /** </span> <span class="hljs-comment">// * 只保存音频不进行播放接口,调用此接口请注释startSpeaking接口</span> <span class="hljs-comment">// * text:要合成的文本,uri:需要保存的音频全路径,listener:回调接口</span> <span class="hljs-comment">// */</span> <span class="hljs-comment">// String path = Environment.getExternalStorageDirectory()+"/tts.pcm";</span> <span class="hljs-comment">// int code = mTts.synthesizeToUri(text, path, mTtsListener);</span> <span class="hljs-keyword">if</span> (code != ErrorCode.SUCCESS) { showTip(<span class="hljs-string">"语音合成失败,错误码: "</span> + code); } } <span class="hljs-keyword">break</span>; } } <span class="hljs-javadoc">/** * 合成回调监听。 */</span> <span class="hljs-keyword">private</span> SynthesizerListener mTtsListener = <span class="hljs-keyword">new</span> SynthesizerListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onSpeakBegin</span>() { showTip(<span class="hljs-string">"开始播放"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onSpeakPaused</span>() { showTip(<span class="hljs-string">"暂停播放"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onSpeakResumed</span>() { showTip(<span class="hljs-string">"继续播放"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onBufferProgress</span>(<span class="hljs-keyword">int</span> percent, <span class="hljs-keyword">int</span> beginPos, <span class="hljs-keyword">int</span> endPos, String info) { <span class="hljs-comment">// 合成进度</span> } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onSpeakProgress</span>(<span class="hljs-keyword">int</span> percent, <span class="hljs-keyword">int</span> beginPos, <span class="hljs-keyword">int</span> endPos) { <span class="hljs-comment">// 播放进度</span> } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCompleted</span>(SpeechError error) { <span class="hljs-keyword">if</span> (error == <span class="hljs-keyword">null</span>) { showTip(<span class="hljs-string">"播放完成"</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (error != <span class="hljs-keyword">null</span>) { showTip(error.getPlainDescription(<span class="hljs-keyword">true</span>)); } } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onEvent</span>(<span class="hljs-keyword">int</span> eventType, <span class="hljs-keyword">int</span> arg1, <span class="hljs-keyword">int</span> arg2, Bundle obj) { <span class="hljs-comment">// 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因</span> <span class="hljs-comment">// 若使用本地能力,会话id为null</span> <span class="hljs-comment">// if (SpeechEvent.EVENT_SESSION_ID == eventType) {</span> <span class="hljs-comment">// String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);</span> <span class="hljs-comment">// Log.d(TAG, "session id =" + sid);</span> <span class="hljs-comment">// }</span> } }; <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTip</span>(<span class="hljs-keyword">final</span> String str) { mToast.setText(str); mToast.show(); } <span class="hljs-javadoc">/** * 参数设置 * *<span class="hljs-javadoctag"> @return</span> */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setParam</span>() { <span class="hljs-comment">// 清空参数</span> mTts.setParameter(SpeechConstant.PARAMS, <span class="hljs-keyword">null</span>); <span class="hljs-comment">// 根据合成引擎设置相应参数</span> mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); <span class="hljs-comment">// 设置在线合成发音人</span> mTts.setParameter(SpeechConstant.VOICE_NAME, <span class="hljs-string">"xiaoyan"</span>); <span class="hljs-comment">//设置合成语速</span> mTts.setParameter(SpeechConstant.SPEED, <span class="hljs-string">"50"</span>); <span class="hljs-comment">//设置合成音调</span> mTts.setParameter(SpeechConstant.PITCH, <span class="hljs-string">"50"</span>); <span class="hljs-comment">//设置合成音量</span> mTts.setParameter(SpeechConstant.VOLUME, <span class="hljs-string">"50"</span>); <span class="hljs-comment">//设置播放器音频流类型</span> mTts.setParameter(SpeechConstant.STREAM_TYPE, <span class="hljs-string">"3"</span>); <span class="hljs-comment">// 设置播放合成音频打断音乐播放,默认为true</span> mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, <span class="hljs-string">"true"</span>); <span class="hljs-comment">// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限</span> <span class="hljs-comment">// 注:AUDIO_FORMAT参数语记需要更新版本才能生效</span> mTts.setParameter(SpeechConstant.AUDIO_FORMAT, <span class="hljs-string">"wav"</span>); mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + <span class="hljs-string">"/msc/tts.wav"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDestroy</span>() { <span class="hljs-keyword">super</span>.onDestroy(); mTts.stopSpeaking(); <span class="hljs-comment">// 退出时释放连接</span> mTts.destroy(); } } </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li><li>151</li><li>152</li><li>153</li><li>154</li><li>155</li><li>156</li><li>157</li><li>158</li><li>159</li><li>160</li><li>161</li><li>162</li><li>163</li><li>164</li><li>165</li><li>166</li><li>167</li><li>168</li><li>169</li><li>170</li><li>171</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li><li>151</li><li>152</li><li>153</li><li>154</li><li>155</li><li>156</li><li>157</li><li>158</li><li>159</li><li>160</li><li>161</li><li>162</li><li>163</li><li>164</li><li>165</li><li>166</li><li>167</li><li>168</li><li>169</li><li>170</li><li>171</li></ul>
使用官方封装的UI,进行语音听写
为了便于开发者调用,讯飞封装了一套用于语音输入的UI。在使用之前需要将官方Demo中的assets目录下的iflytek放到你的项目的assets目录下。其内容如下:
展示界面的布局文件
<code class="hljs xml has-numbering"><span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span> <span class="hljs-comment"><!--activity_speech2text_ui.xml--></span> <span class="hljs-tag"><<span class="hljs-title">LinearLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:focusable</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:focusableInTouchMode</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"center_horizontal"</span> <span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"vertical"</span> <span class="hljs-attribute">android:paddingLeft</span>=<span class="hljs-value">"10dp"</span> <span class="hljs-attribute">android:paddingRight</span>=<span class="hljs-value">"10dp"</span>></span> <span class="hljs-tag"><<span class="hljs-title">TextView </span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_centerInParent</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"讯飞听写示例"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"30sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">EditText </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_text"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"top|left"</span> <span class="hljs-attribute">android:paddingBottom</span>=<span class="hljs-value">"20dp"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_recognize"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"开始"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul>
java代码:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.iflytek.voicedemo; <span class="hljs-keyword">import</span> android.Manifest; <span class="hljs-keyword">import</span> android.annotation.SuppressLint; <span class="hljs-keyword">import</span> android.app.Activity; <span class="hljs-keyword">import</span> android.os.Bundle; <span class="hljs-keyword">import</span> android.support.v4.app.ActivityCompat; <span class="hljs-keyword">import</span> android.view.View; <span class="hljs-keyword">import</span> android.view.View.OnClickListener; <span class="hljs-keyword">import</span> android.view.Window; <span class="hljs-keyword">import</span> android.widget.EditText; <span class="hljs-keyword">import</span> android.widget.Toast; <span class="hljs-keyword">import</span> com.iflytek.cloud.RecognizerResult; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechError; <span class="hljs-keyword">import</span> com.iflytek.cloud.ui.RecognizerDialog; <span class="hljs-keyword">import</span> com.iflytek.cloud.ui.RecognizerDialogListener; <span class="hljs-keyword">import</span> com.iflytek.speech.util.JsonParser; <span class="hljs-keyword">import</span> org.json.JSONException; <span class="hljs-keyword">import</span> org.json.JSONObject; <span class="hljs-keyword">import</span> java.util.HashMap; <span class="hljs-keyword">import</span> java.util.LinkedHashMap; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Speech2TextUIActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OnClickListener</span> {</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String TAG = Speech2TextUIActivity.class.getSimpleName(); <span class="hljs-comment">// 语音听写UI</span> <span class="hljs-keyword">private</span> RecognizerDialog mIatDialog; <span class="hljs-comment">// 用HashMap存储听写结果</span> <span class="hljs-keyword">private</span> HashMap<String, String> mIatResults = <span class="hljs-keyword">new</span> LinkedHashMap<String, String>(); <span class="hljs-keyword">private</span> EditText mResultText; <span class="hljs-keyword">private</span> Toast mToast; <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"ShowToast"</span>) <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_speech2text_ui); findViewById(R.id.iat_recognize).setOnClickListener(<span class="hljs-keyword">this</span>); <span class="hljs-comment">// 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer</span> <span class="hljs-comment">// 使用UI听写功能,放置布局文件和图片资源</span> <span class="hljs-comment">//使用云服务InitListener参数写成null</span> mIatDialog = <span class="hljs-keyword">new</span> RecognizerDialog(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">null</span>); mToast = Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">""</span>, Toast.LENGTH_SHORT); mResultText = ((EditText) findViewById(R.id.iat_text)); applyPermission(); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">applyPermission</span>() { ActivityCompat.requestPermissions(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">new</span> String[]{Manifest.permission.RECORD_AUDIO}, <span class="hljs-number">12</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View view) { <span class="hljs-keyword">switch</span> (view.getId()) { <span class="hljs-comment">// 开始听写</span> <span class="hljs-comment">// 如何判断一次听写结束:OnResult isLast=true 或者 onError</span> <span class="hljs-keyword">case</span> R.id.iat_recognize: mResultText.setText(<span class="hljs-keyword">null</span>);<span class="hljs-comment">// 清空显示内容</span> mIatResults.clear(); <span class="hljs-comment">// 显示听写对话框</span> mIatDialog.setListener(mRecognizerDialogListener); mIatDialog.show(); showTip(<span class="hljs-string">"请开始说话…"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">default</span>: <span class="hljs-keyword">break</span>; } } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printResult</span>(RecognizerResult results) { String text = JsonParser.parseIatResult(results.getResultString()); String sn = <span class="hljs-keyword">null</span>; <span class="hljs-comment">// 读取json结果中的sn字段</span> <span class="hljs-keyword">try</span> { JSONObject resultJson = <span class="hljs-keyword">new</span> JSONObject(results.getResultString()); sn = resultJson.optString(<span class="hljs-string">"sn"</span>); } <span class="hljs-keyword">catch</span> (JSONException e) { e.printStackTrace(); } mIatResults.put(sn, text); StringBuffer resultBuffer = <span class="hljs-keyword">new</span> StringBuffer(); <span class="hljs-keyword">for</span> (String key : mIatResults.keySet()) { resultBuffer.append(mIatResults.get(key)); } mResultText.setText(resultBuffer.toString()); mResultText.setSelection(mResultText.length()); } <span class="hljs-javadoc">/** * 听写UI监听器 */</span> <span class="hljs-keyword">private</span> RecognizerDialogListener mRecognizerDialogListener = <span class="hljs-keyword">new</span> RecognizerDialogListener() { <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResult</span>(RecognizerResult results, <span class="hljs-keyword">boolean</span> isLast) { printResult(results); } <span class="hljs-javadoc">/** * 识别回调错误. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span>(SpeechError error) { showTip(error.getPlainDescription(<span class="hljs-keyword">true</span>)); } }; <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTip</span>(<span class="hljs-keyword">final</span> String str) { mToast.setText(str); mToast.show(); } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li></ul>
解释服务器返回数据,用到的工具类
<code class="hljs avrasm has-numbering">package <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.iflytek</span><span class="hljs-preprocessor">.speech</span><span class="hljs-preprocessor">.util</span><span class="hljs-comment">;</span> import org<span class="hljs-preprocessor">.json</span><span class="hljs-preprocessor">.JSONArray</span><span class="hljs-comment">;</span> import org<span class="hljs-preprocessor">.json</span><span class="hljs-preprocessor">.JSONObject</span><span class="hljs-comment">;</span> import org<span class="hljs-preprocessor">.json</span><span class="hljs-preprocessor">.JSONTokener</span><span class="hljs-comment">;</span> import android<span class="hljs-preprocessor">.util</span><span class="hljs-preprocessor">.Log</span><span class="hljs-comment">;</span> <span class="hljs-comment">/** * Json结果解析类 */</span> public class JsonParser { public static String parseIatResult(String json) { StringBuffer <span class="hljs-keyword">ret</span> = new StringBuffer()<span class="hljs-comment">;</span> try { JSONObject joResult = new JSONObject(json)<span class="hljs-comment">;</span> JSONArray words = joResult<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"ws"</span>)<span class="hljs-comment">;</span> for (int i = <span class="hljs-number">0</span><span class="hljs-comment">; i < words.length(); i++) {</span> // 转写结果词,默认使用第一个结果 JSONArray items = words<span class="hljs-preprocessor">.getJSONObject</span>(i)<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"cw"</span>)<span class="hljs-comment">;</span> JSONObject obj = items<span class="hljs-preprocessor">.getJSONObject</span>(<span class="hljs-number">0</span>)<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>))<span class="hljs-comment">;</span> // 如果需要多候选结果,解析数组其他字段 // for(int j = <span class="hljs-number">0</span><span class="hljs-comment">; j < items.length(); j++)</span> // { // JSONObject obj = items<span class="hljs-preprocessor">.getJSONObject</span>(j)<span class="hljs-comment">;</span> // <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>))<span class="hljs-comment">;</span> // } } } catch (Exception e) { e<span class="hljs-preprocessor">.printStackTrace</span>()<span class="hljs-comment">;</span> } return <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.toString</span>()<span class="hljs-comment">;</span> } public static String parseGrammarResult(String json) { StringBuffer <span class="hljs-keyword">ret</span> = new StringBuffer()<span class="hljs-comment">;</span> try { JSONTokener tokener = new JSONTokener(json)<span class="hljs-comment">;</span> JSONObject joResult = new JSONObject(tokener)<span class="hljs-comment">;</span> JSONArray words = joResult<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"ws"</span>)<span class="hljs-comment">;</span> for (int i = <span class="hljs-number">0</span><span class="hljs-comment">; i < words.length(); i++) {</span> JSONArray items = words<span class="hljs-preprocessor">.getJSONObject</span>(i)<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"cw"</span>)<span class="hljs-comment">;</span> for(int j = <span class="hljs-number">0</span><span class="hljs-comment">; j < items.length(); j++)</span> { JSONObject obj = items<span class="hljs-preprocessor">.getJSONObject</span>(j)<span class="hljs-comment">;</span> if(obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>)<span class="hljs-preprocessor">.contains</span>(<span class="hljs-string">"nomatch"</span>)) { <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"没有匹配结果."</span>)<span class="hljs-comment">;</span> return <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.toString</span>()<span class="hljs-comment">;</span> } <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"【结果】"</span> + obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>))<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"【置信度】"</span> + obj<span class="hljs-preprocessor">.getInt</span>(<span class="hljs-string">"sc"</span>))<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"\n"</span>)<span class="hljs-comment">;</span> } } } catch (Exception e) { e<span class="hljs-preprocessor">.printStackTrace</span>()<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"没有匹配结果."</span>)<span class="hljs-comment">;</span> } return <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.toString</span>()<span class="hljs-comment">;</span> } public static String parseLocalGrammarResult(String json) { StringBuffer <span class="hljs-keyword">ret</span> = new StringBuffer()<span class="hljs-comment">;</span> try { JSONTokener tokener = new JSONTokener(json)<span class="hljs-comment">;</span> JSONObject joResult = new JSONObject(tokener)<span class="hljs-comment">;</span> JSONArray words = joResult<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"ws"</span>)<span class="hljs-comment">;</span> for (int i = <span class="hljs-number">0</span><span class="hljs-comment">; i < words.length(); i++) {</span> JSONArray items = words<span class="hljs-preprocessor">.getJSONObject</span>(i)<span class="hljs-preprocessor">.getJSONArray</span>(<span class="hljs-string">"cw"</span>)<span class="hljs-comment">;</span> for(int j = <span class="hljs-number">0</span><span class="hljs-comment">; j < items.length(); j++)</span> { JSONObject obj = items<span class="hljs-preprocessor">.getJSONObject</span>(j)<span class="hljs-comment">;</span> if(obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>)<span class="hljs-preprocessor">.contains</span>(<span class="hljs-string">"nomatch"</span>)) { <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"没有匹配结果."</span>)<span class="hljs-comment">;</span> return <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.toString</span>()<span class="hljs-comment">;</span> } <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"【结果】"</span> + obj<span class="hljs-preprocessor">.getString</span>(<span class="hljs-string">"w"</span>))<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"\n"</span>)<span class="hljs-comment">;</span> } } <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"【置信度】"</span> + joResult<span class="hljs-preprocessor">.optInt</span>(<span class="hljs-string">"sc"</span>))<span class="hljs-comment">;</span> } catch (Exception e) { e<span class="hljs-preprocessor">.printStackTrace</span>()<span class="hljs-comment">;</span> <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.append</span>(<span class="hljs-string">"没有匹配结果."</span>)<span class="hljs-comment">;</span> } return <span class="hljs-keyword">ret</span><span class="hljs-preprocessor">.toString</span>()<span class="hljs-comment">;</span> } } </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li></ul>
官方定制的UI还是挺漂亮的!
不使用官方UI控件进行语音听写
使用到的布局文件如下:
<code class="hljs xml has-numbering"><span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span> <span class="hljs-comment"><!--activity_speech2text.xml--></span> <span class="hljs-tag"><<span class="hljs-title">LinearLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:focusable</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:focusableInTouchMode</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"center_horizontal"</span> <span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"vertical"</span> <span class="hljs-attribute">android:paddingLeft</span>=<span class="hljs-value">"10dp"</span> <span class="hljs-attribute">android:paddingRight</span>=<span class="hljs-value">"10dp"</span>></span> <span class="hljs-tag"><<span class="hljs-title">TextView </span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_centerInParent</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"讯飞听写示例"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"30sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">EditText </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_text"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"top|left"</span> <span class="hljs-attribute">android:paddingBottom</span>=<span class="hljs-value">"20dp"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">LinearLayout </span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_marginBottom</span>=<span class="hljs-value">"2dp"</span> <span class="hljs-attribute">android:layout_marginTop</span>=<span class="hljs-value">"10dp"</span> <span class="hljs-attribute">android:gravity</span>=<span class="hljs-value">"center_horizontal"</span> <span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"horizontal"</span>></span> <span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_recognize"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"开始"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_stop"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"停止"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/iat_cancel"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"0dp"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> <span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span> <span class="hljs-attribute">android:text</span>=<span class="hljs-value">"取消"</span> <span class="hljs-attribute">android:textSize</span>=<span class="hljs-value">"20sp"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span> <span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li></ul>
java代码:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.iflytek.voicedemo; <span class="hljs-keyword">import</span> android.Manifest; <span class="hljs-keyword">import</span> android.annotation.SuppressLint; <span class="hljs-keyword">import</span> android.app.Activity; <span class="hljs-keyword">import</span> android.os.Bundle; <span class="hljs-keyword">import</span> android.support.v4.app.ActivityCompat; <span class="hljs-keyword">import</span> android.util.Log; <span class="hljs-keyword">import</span> android.view.View; <span class="hljs-keyword">import</span> android.view.View.OnClickListener; <span class="hljs-keyword">import</span> android.view.Window; <span class="hljs-keyword">import</span> android.widget.EditText; <span class="hljs-keyword">import</span> android.widget.Toast; <span class="hljs-keyword">import</span> com.iflytek.cloud.ErrorCode; <span class="hljs-keyword">import</span> com.iflytek.cloud.RecognizerListener; <span class="hljs-keyword">import</span> com.iflytek.cloud.RecognizerResult; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechConstant; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechError; <span class="hljs-keyword">import</span> com.iflytek.cloud.SpeechRecognizer; <span class="hljs-keyword">import</span> com.iflytek.speech.util.JsonParser; <span class="hljs-keyword">import</span> org.json.JSONException; <span class="hljs-keyword">import</span> org.json.JSONObject; <span class="hljs-keyword">import</span> java.util.HashMap; <span class="hljs-keyword">import</span> java.util.LinkedHashMap; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Speech2TextActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OnClickListener</span> {</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String TAG = Speech2TextActivity.class.getSimpleName(); <span class="hljs-comment">// 语音听写对象</span> <span class="hljs-keyword">private</span> SpeechRecognizer mIat; <span class="hljs-comment">// 用HashMap存储听写结果</span> <span class="hljs-keyword">private</span> HashMap<String, String> mIatResults = <span class="hljs-keyword">new</span> LinkedHashMap<String, String>(); <span class="hljs-keyword">private</span> EditText mResultText; <span class="hljs-keyword">private</span> Toast mToast; <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"ShowToast"</span>) <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_speech2text); findViewById(R.id.iat_recognize).setOnClickListener(Speech2TextActivity.<span class="hljs-keyword">this</span>); findViewById(R.id.iat_stop).setOnClickListener(Speech2TextActivity.<span class="hljs-keyword">this</span>); findViewById(R.id.iat_cancel).setOnClickListener(Speech2TextActivity.<span class="hljs-keyword">this</span>); mIat = SpeechRecognizer.createRecognizer(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">null</span>); mToast = Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">""</span>, Toast.LENGTH_SHORT); mResultText = ((EditText) findViewById(R.id.iat_text)); applyPermission(); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">applyPermission</span>() { ActivityCompat.requestPermissions(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">new</span> String[]{Manifest.permission.RECORD_AUDIO}, <span class="hljs-number">12</span>); } <span class="hljs-keyword">int</span> ret = <span class="hljs-number">0</span>; <span class="hljs-comment">// 函数调用返回值</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View view) { <span class="hljs-keyword">switch</span> (view.getId()) { <span class="hljs-comment">// 开始听写</span> <span class="hljs-comment">// 如何判断一次听写结束:OnResult isLast=true 或者 onError</span> <span class="hljs-keyword">case</span> R.id.iat_recognize: mResultText.setText(<span class="hljs-keyword">null</span>);<span class="hljs-comment">// 清空显示内容</span> mIatResults.clear(); <span class="hljs-comment">// 设置参数</span> setParam(); ret = mIat.startListening(mRecognizerListener); <span class="hljs-keyword">if</span> (ret != ErrorCode.SUCCESS) { showTip(<span class="hljs-string">"听写失败,错误码:"</span> + ret); } <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> R.id.iat_stop: mIat.stopListening(); showTip(<span class="hljs-string">"停止听写"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> R.id.iat_cancel: mIat.cancel(); showTip(<span class="hljs-string">"取消听写"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">default</span>: <span class="hljs-keyword">break</span>; } } <span class="hljs-javadoc">/** * 听写监听器。 */</span> <span class="hljs-keyword">private</span> RecognizerListener mRecognizerListener = <span class="hljs-keyword">new</span> RecognizerListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onBeginOfSpeech</span>() { <span class="hljs-comment">// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入</span> showTip(<span class="hljs-string">"开始说话"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span>(SpeechError error) { <span class="hljs-comment">// Tips:</span> <span class="hljs-comment">// 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。</span> <span class="hljs-comment">// 如果使用本地功能(语记)需要提示用户开启语记的录音权限。</span> showTip(error.getPlainDescription(<span class="hljs-keyword">true</span>)); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onEndOfSpeech</span>() { <span class="hljs-comment">// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入</span> showTip(<span class="hljs-string">"结束说话"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResult</span>(RecognizerResult results, <span class="hljs-keyword">boolean</span> isLast) { Log.d(TAG, results.getResultString()); printResult(results); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onVolumeChanged</span>(<span class="hljs-keyword">int</span> volume, <span class="hljs-keyword">byte</span>[] data) { showTip(<span class="hljs-string">"当前正在说话,音量大小:"</span> + volume); Log.d(TAG, <span class="hljs-string">"返回音频数据:"</span> + data.length); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onEvent</span>(<span class="hljs-keyword">int</span> eventType, <span class="hljs-keyword">int</span> arg1, <span class="hljs-keyword">int</span> arg2, Bundle obj) { <span class="hljs-comment">// 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因</span> <span class="hljs-comment">// 若使用本地能力,会话id为null</span> <span class="hljs-comment">// if (SpeechEvent.EVENT_SESSION_ID == eventType) {</span> <span class="hljs-comment">// String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);</span> <span class="hljs-comment">// Log.d(TAG, "session id =" + sid);</span> <span class="hljs-comment">// }</span> } }; <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printResult</span>(RecognizerResult results) { String text = JsonParser.parseIatResult(results.getResultString()); String sn = <span class="hljs-keyword">null</span>; <span class="hljs-comment">// 读取json结果中的sn字段</span> <span class="hljs-keyword">try</span> { JSONObject resultJson = <span class="hljs-keyword">new</span> JSONObject(results.getResultString()); sn = resultJson.optString(<span class="hljs-string">"sn"</span>); } <span class="hljs-keyword">catch</span> (JSONException e) { e.printStackTrace(); } mIatResults.put(sn, text); StringBuffer resultBuffer = <span class="hljs-keyword">new</span> StringBuffer(); <span class="hljs-keyword">for</span> (String key : mIatResults.keySet()) { resultBuffer.append(mIatResults.get(key)); } mResultText.setText(resultBuffer.toString()); mResultText.setSelection(mResultText.length()); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTip</span>(<span class="hljs-keyword">final</span> String str) { mToast.setText(str); mToast.show(); } <span class="hljs-javadoc">/** * 参数设置 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setParam</span>() { <span class="hljs-comment">// 清空参数</span> mIat.setParameter(SpeechConstant.PARAMS, <span class="hljs-keyword">null</span>); <span class="hljs-comment">// 设置听写引擎</span> mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); <span class="hljs-comment">// 设置返回结果格式</span> mIat.setParameter(SpeechConstant.RESULT_TYPE, <span class="hljs-string">"json"</span>); <span class="hljs-comment">// 设置语言</span> mIat.setParameter(SpeechConstant.LANGUAGE, <span class="hljs-string">"zh_cn"</span>); <span class="hljs-comment">// 设置语言区域</span> mIat.setParameter(SpeechConstant.ACCENT, <span class="hljs-string">"mandarin"</span>); <span class="hljs-comment">// 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理</span> mIat.setParameter(SpeechConstant.VAD_BOS, <span class="hljs-string">"4000"</span>); <span class="hljs-comment">// 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音</span> mIat.setParameter(SpeechConstant.VAD_EOS, <span class="hljs-string">"1000"</span>); <span class="hljs-comment">// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点</span> mIat.setParameter(SpeechConstant.ASR_PTT, <span class="hljs-string">"1"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDestroy</span>() { <span class="hljs-keyword">super</span>.onDestroy(); <span class="hljs-comment">// 退出时释放连接</span> mIat.cancel(); mIat.destroy(); } }</code>