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

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

转载自:http://blog.csdn.net/highboys/article/details/52145038

一、语音识别

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中添加一下权限
<!--连接网络权限,用于执行云端语音能力 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!--读取网络信息状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--获取当前wifi状态 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--允许程序改变网络连接状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <!--读取手机信息权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <!--SD卡读写的权限(如果需要保存音频文件到本地的话)-->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
其次是java代码(逻辑上是点击了某个Button之后,才执行下面的代码)。
//有动画效果
    private RecognizerDialog iatDialog;
// ①语音配置对象初始化
                SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID + "=578f1af7");//将这里的578f1af7替换成自己申请得到的8位appid
                // ②初始化有交互动画的语音识别器
                iatDialog = new RecognizerDialog(MainActivity.this, mInitListener);
  //③设置监听,实现听写结果的回调
                iatDialog.setListener(new RecognizerDialogListener() {
                    String resultJson = "[";//放置在外边做类的变量则报错,会造成json格式不对(?)

                    @Override
                    public void onResult(RecognizerResult recognizerResult, boolean isLast) {
                        System.out.println("----------------- onResult -----------------");
                        if (!isLast) {
                            resultJson += recognizerResult.getResultString() + ",";
                        } else {
                            resultJson += recognizerResult.getResultString() + "]";
                        }

                        if (isLast) {
                            //解析语音识别后返回的json格式的结果
                            Gson gson = new Gson();
                            List<DictationResult> resultList = gson.fromJson(resultJson,
                                    new TypeToken<List<DictationResult>>() {
                                    }.getType());
                            String result = "";
                            for (int i = 0; i < resultList.size() - 1; i++) {
                                result += resultList.get(i).toString();
                            }
                            etText.setText(result);
                            //获取焦点
                            etText.requestFocus();
                            //将光标定位到文字最后,以便修改
                            etText.setSelection(result.length());
                        }
                    }

                    @Override
                    public void onError(SpeechError speechError) {
                        //自动生成的方法存根
                        speechError.getPlainDescription(true);
                    }
                });
                //开始听写,需将sdk中的assets文件下的文件夹拷入项目的assets文件夹下(没有的话自己新建)
                iatDialog.show();
其中的mInitListener定义如下:(此处写在方法外即可)
public static final String TAG = "MainActivity";
    private InitListener mInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
            Log.d(TAG, "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                Toast.makeText(MainActivity.this, "初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();
            }
        }
    };

上面的代码用到了一个DictationResult类(一个用来接收转换 语音听写结果的类),需要自己新建,定义如下
/**
 * 解析 语音听写返回结果Json格式字符串 的模板类(多重嵌套Json)
 *
 * 语音识别结果Json数据格式(单条数据):
 * {"sn":1,"ls":true,"bg":0,"ed":0,"ws":[
 * {"bg":0,"cw":[{"w":"今天","sc":0}]},
 * {"bg":0,"cw":[{"w":"的","sc":0}]},
 * {"bg":0,"cw":[{"w":"天气","sc":0}]},
 * {"bg":0,"cw":[{"w":"怎么样","sc":0}]},
 * {"bg":0,"cw":[{"w":"。","sc":0}]}
 * ]}
 *
 * sn number :第几句
 * ls boolean: 是否最后一句
 * bg number :开始
 * ed number :结束
 * ws array :词
 * cw array :中文分词
 * w string :单字
 * sc number :分数
 */
public class DictationResult {
    private String sn;
    private String ls;
    private String bg;
    private String ed;

    private List<Words> ws;

    public static class Words {
        private String bg;
        private List<Cw> cw;

        public static class Cw {
            private String w;
            private String sc;

            public String getW() {
                return w;
            }

            public void setW(String w) {
                this.w = w;
            }

            public String getSc() {
                return sc;
            }

            public void setSc(String sc) {
                this.sc = sc;
            }

            @Override
            public String toString() {
                return w;
            }
        }

        public String getBg() {
            return bg;
        }

        public void setBg(String bg) {
            this.bg = bg;
        }

        public List<Cw> getCw() {
            return cw;
        }

        public void setCw(List<Cw> cw) {
            this.cw = cw;
        }

        @Override
        public String toString() {
            String result = "";
            for (Cw cwTmp : cw) {
                result += cwTmp.toString();
            }
            return result;
        }
    }

    public String getSn() {
        return sn;
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public String getLs() {
        return ls;
    }

    public void setLs(String ls) {
        this.ls = ls;
    }

    public String getBg() {
        return bg;
    }

    public void setBg(String bg) {
        this.bg = bg;
    }

    public String getEd() {
        return ed;
    }

    public void setEd(String ed) {
        this.ed = ed;
    }

    public List<Words> getWs() {
        return ws;
    }

    public void setWs(List<Words> ws) {
        this.ws = ws;
    }

    @Override
    public String toString() {
        String result = "";
        for (Words wsTmp : ws) {
            result += wsTmp.toString();
        }
        return result;
    }
}

如此,便可实现语音听写了。这个过程可能会遇到各种各样的问题,具体错误码参见  http://www.xfyun.cn/doccenter/faq
5.说完了有动画效果的,下面就来说说没有动画效果的(也比较简单)。
//1.创建SpeechRecognizer对象,第二个参数:本地识别时传InitListener
    SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(context, null);
    //2.设置听写参数,详见SDK中《MSC Reference Manual》文件夹下的SpeechConstant类
    mIat.setParameter(SpeechConstant.DOMAIN,"iat");
    mIat.setParameter(SpeechConstant.LANGUAGE,"zh_cn");
    mIat.setParameter(SpeechConstant.ACCENT,"mandarin ");

      //保存音频文件到本地(有需要的话) 仅支持pcm和wav,且需要自行添加读写SD卡权限
    mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/mIat.wav");
    // 3.开始听写
    mIat.startListening(mRecoListener);
    //听写监听器
    private RecognizerListener mRecoListener = new RecognizerListener() {
        //听写结果回调接口(返回Json格式结果,用户可参见附录13.1);
        // 一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
        // 关于解析Json的代码可参见Demo中JsonParser类;
        // isLast等于true时会话结束。
        public void onResult(RecognizerResult results, boolean isLast) {
            Log.d(TAG, "result:" + results.getResultString());
        }

        //会话发生错误回调接口
        public void onError(SpeechError error) {
            //打印错误码描述
            Log.d(TAG, "error:" + error.getPlainDescription(true))
        }

        //开始录音
        public void onBeginOfSpeech() {
        }

        // volume音量值0~30,data音频数据
        public void onVolumeChanged(int volume, byte[] data) {
        }

        //结束录音
        public void onEndOfSpeech() {
        }

        //扩展用接口
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
        }
    };

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

效果图:

二、语音合成

1.语音合成也需要创建语音配置对象:
SpeechUtility.createUtility(MainActivity.this, SpeechConstant.APPID + "=578f1af7");
2.创建用于语音合成的对象并设置参数,进行语音合成
//1.创建SpeechSynthesizer对象, 第二个参数:本地合成时传InitListener
        SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(MainActivity.this, null);

        /**
         2.合成参数设置,详见《科大讯飞MSC API手册(Android)》SpeechSynthesizer 类
         */
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);

        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置云端
        mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");//设置发音人
        mTts.setParameter(SpeechConstant.SPEED, "50");//设置语速
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, "50");
        mTts.setParameter(SpeechConstant.VOLUME, "80");//设置音量,范围0~100
        mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
        // 设置播放合成音频打断音乐播放,默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
// mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
// boolean isSuccess = mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts2.wav");
// Toast.makeText(MainActivity.this, "语音合成 保存音频到本地:\n" + isSuccess, Toast.LENGTH_LONG).show();
        //3.开始合成
        int code = mTts.startSpeaking("在这里放置需要进行合成的文本", mSynListener);

        if (code != ErrorCode.SUCCESS) {
            if (code == ErrorCode.ERROR_COMPONENT_NOT_INSTALLED) {
                //上面的语音配置对象为初始化时:
                Toast.makeText(MainActivity.this, "语音组件未安装", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "语音合成失败,错误码: " + code, Toast.LENGTH_LONG).show();
            }
        }

合成时需要一个SynthesizerListener类型的合成监听器作参数,定义如下
//合成监听器
    private SynthesizerListener mSynListener = new SynthesizerListener() {
        //会话结束回调接口,没有错误时,error为null
        public void onCompleted(SpeechError error) {
        }

        //缓冲进度回调
        //percent为缓冲进度0~100,beginPos为缓冲音频在文本中开始位置,endPos表示缓冲音频在文本中结束位置,info为附加信息。
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
        }

        //开始播放
        public void onSpeakBegin() {
        }

        //暂停播放
        public void onSpeakPaused() {
        }

        //播放进度回调
        //percent为播放进度0~100,beginPos为播放音频在文本中开始位置,endPos表示播放音频在文本中结束位置.
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
        }

        //恢复播放回调接口
        public void onSpeakResumed() {
        }

        //会话事件回调接口
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
        }
    };
本文参照SDK中doc文件夹下的  MSC Develop Manual for Android.pdf 文件完成,里边写得很详细。也可参见   http://www.xfyun.cn/doccenter/awd   。
效果:

错误码
10000~19999的错误码参见 MSC错误码
其它错误码参见下表:
错误码 数值 含义
ERROR_NO_NETWORK 20001 无有效的网络连接
ERROR_NETWORK_TIMEOUT 20002 网络连接超时
ERROR_NET_EXPECTION 20003 网络连接发生异常
ERROR_INVALID_RESULT 20004 无有效的结果
ERROR_NO_MATCH 20005 无匹配结果
ERROR_AUDIO_RECORD 20006 录音失败
ERROR_NO_SPPECH 20007 未检测到语音
ERROR_SPEECH_TIMEOUT 20008 音频输入超时
ERROR_EMPTY_UTTERANCE 20009 无效的文本输入
ERROR_FILE_ACCESS 20010 文件读写失败
ERROR_PLAY_MEDIA 20011 音频播放失败
ERROR_INVALID_PARAM 20012 无效的参数
ERROR_TEXT_OVERFLOW 20013 文本溢出
ERROR_INVALID_DATA 20014 无效数据
ERROR_LOGIN 20015 用户未登陆
ERROR_PERMISSION_DENIED 20016 无效授权
ERROR_INTERRUPT 20017 被异常打断
ERROR_VERSION_LOWER 20018 版本过低
ERROR_COMPONENT_NOT_INSTALLED 21001 没有安装语音组件
ERROR_ENGINE_NOT_SUPPORTED 21002 引擎不支持
ERROR_ENGINE_INIT_FAIL 21003 初始化失败
ERROR_ENGINE_CALL_FAIL 21004 调用失败
ERROR_ENGINE_BUSY 21005 引擎繁忙
ERROR_LOCAL_NO_INIT 22001 本地引擎未初始化
ERROR_LOCAL_RESOURCE 22002 本地引擎无资源
ERROR_LOCAL_ENGINE 22003 本地引擎内部错误
ERROR_IVW_INTERRUPT 22004 本地唤醒引擎被异常打断
ERROR_UNKNOWN 20999 未知错误
合成发音人列表
  1. 语言为中英文的发音人可以支持中英文的混合朗读。
  2. 英文发音人只能朗读英文,中文无法朗读。
  3. 汉语发音人只能朗读中文,遇到英文会以单个字母的方式进行朗读。
  4. 使用新引擎参数会获得更好的合成效果。
名称 属性 语言 参数名称 新引擎参数 备注
小燕青年女声中英文
(普通话)
xiaoyan 默认
小宇青年男声中英文
(普通话)
xiaoyu  
凯瑟琳青年女声英文catherine  
亨利青年男声英文henry  
玛丽青年女声英文vimary  
小研青年女声中英文
(普通话)
vixy  
小琪青年女声中英文
(普通话)
vixqxiaoqi 
小峰青年男声中英文
(普通话)
vixf  
小梅青年女声中英文
(粤语)
vixmxiaomei 
小莉青年女声中英文
(台湾普通话)
vixl  
晓琳青年女声中英文
(台湾普通话)
 xiaolin 
小蓉青年女声汉语
(四川话)
vixrxiaorong 
小芸青年女声汉语
(东北话)
vixyun  
小倩青年女声汉语
(东北话)
 xiaoqian 
小坤青年男声汉语
(河南话)
vixkxiaokun 
小强青年男声汉语
(湖南话)
vixqaxiaoqiang 
小莹青年女声汉语
(陕西话)
vixying  
小新童年男声汉语
(普通话)
vixxxiaoxin 
楠楠童年女声汉语
(普通话)
vinnnannan 
老孙老年男声汉语
(普通话)
vils  
Mariane 法语Mariane  
Allabent 俄语Allabent  
Gabriela 西班牙语Gabriela  
Abha 印地语Abha  
XiaoYun   越南语 XiaoYun   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值