集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(在线)

集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(离在线融合)


    上一篇是写的在线语音合成,用的是科大讯飞的SDK,因为在线是需要网络的,所以离线也是有需求的,至于为什么不直接用离在线,下一篇再告诉大家,这里先卖个关子,这一篇就写离线语音合成,用的是云知声的SDK。

首先,打开云知声开放平台


然后,注册、登录(图略)

接着打开我的应用,添加新应用,选择通用解决方案


添加新应用后,选择Android,离线语音合成,点击下载



下载完成后,解压压缩包USCDemo文件夹

打开USCDemo-->assets-->OfflineTTSModels,选择复制2个文件(离线语音合成模型到你项目中的assets资源目录下


打开USCDemo-->libs,复制jar包和.so文件到你的项目libs目录下


注意:需要在build.gradle增加如下图所示代码(注意层级),不然编译时会报错找不到.so文件(如下图左上角箭头修改项目结构为Project,然后找到在app目录下的build.gradle文件进行修改)

repositories {    flatDir {        dir 'libs'    }}
sourceSets {    main {        jniLibs.srcDir 'libs'    }}

做完以上准备工作,就可以开始撸代码了

    首先,AndroidManifest.xml申请权限(6.0需要动态申请权限,碍于篇幅,请自行百度)
                                                
    然后,直接封装成工具类,以供全局调用离线语音合成功能,大家可以直接复制进去用,其中APPKEY和SECRET在开放平台-->我的应用,点击你之前添加的应用可查看
package com.cyf.ttsdemo.utils;import android.content.Context;import android.os.Environment;import android.util.Log;import com.cyf.ttsdemo.MyApplication;import com.unisound.client.SpeechConstants;import com.unisound.client.SpeechSynthesizer;import com.unisound.client.SpeechSynthesizerListener;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;/** * Created by As on 2017/8/7. */public class TTSUtils implements SpeechSynthesizerListener {    private static final String TAG = "TTSUtils";    private static volatile TTSUtils instance = null;    private boolean isInitSuccess = false;    private SpeechSynthesizer mTTSPlayer;    private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/unisound/tts/";    private static final String FRONTEND_MODEL = "frontend_model";    private static final String BACKEND_MODEL = "backend_lzl";    private static final String APPKEY = "wiouzjcsmxvqes7ibqqm5bcgqrzrvddsvtceiwa5";    private static final String SECRET = "3e20d7aff586ffe7dce62b302e7cc378";    private TTSUtils() {    }    public static TTSUtils getInstance() {        if (instance == null) {            synchronized (TTSUtils.class) {                if (instance == null) {                    instance = new TTSUtils();                }            }        }        return instance;    }    public void init() {        Context context = MyApplication.getContext();        mTTSPlayer = new SpeechSynthesizer(context, APPKEY, SECRET);        mTTSPlayer.setOption(SpeechConstants.TTS_SERVICE_MODE, SpeechConstants.TTS_SERVICE_MODE_LOCAL); // 设置本地合成File file = new File(SAMPLE_DIR);        if (!file.exists()) {            file.mkdirs();        }        File _FrontendModelFile = new File(SAMPLE_DIR + FRONTEND_MODEL);        if (!_FrontendModelFile.exists()) {            copyAssetsFile2SDCard(context, FRONTEND_MODEL, SAMPLE_DIR + FRONTEND_MODEL);        }        File _BackendModelFile = new File(SAMPLE_DIR + BACKEND_MODEL);        if (!_BackendModelFile.exists()) {            copyAssetsFile2SDCard(context, BACKEND_MODEL, SAMPLE_DIR + BACKEND_MODEL);        }        mTTSPlayer.setOption(SpeechConstants.TTS_KEY_FRONTEND_MODEL_PATH, SAMPLE_DIR + FRONTEND_MODEL);// 设置前端模型        mTTSPlayer.setOption(SpeechConstants.TTS_KEY_BACKEND_MODEL_PATH, SAMPLE_DIR + BACKEND_MODEL);// 设置后端模型        mTTSPlayer.setTTSListener(this);// 设置回调监听        mTTSPlayer.init(null);// 初始化合成引擎    }    public void speak(String msg) {        if (isInitSuccess) {            mTTSPlayer.playText(msg);        }else {            init();        }    }    public void stop() {        mTTSPlayer.stop();    }    public void pause() {        mTTSPlayer.pause();    }    public void resume() {        mTTSPlayer.resume();    }    public void release() {        if (null != mTTSPlayer) {            // 释放离线引擎            mTTSPlayer.release(SpeechConstants.TTS_RELEASE_ENGINE, null);        }    }    @Override    public void onEvent(int type) {        switch (type) {            case SpeechConstants.TTS_EVENT_INIT:                isInitSuccess = true;                break;            case SpeechConstants.TTS_EVENT_SYNTHESIZER_START:                // 开始合成回调                Log.i(TAG, "beginSynthesizer");                break;            case SpeechConstants.TTS_EVENT_SYNTHESIZER_END:                // 合成结束回调                Log.i(TAG, "endSynthesizer");                break;            case SpeechConstants.TTS_EVENT_BUFFER_BEGIN:                // 开始缓存回调                Log.i(TAG, "beginBuffer");                break;            case SpeechConstants.TTS_EVENT_BUFFER_READY:                // 缓存完毕回调                Log.i(TAG, "bufferReady");                break;            case SpeechConstants.TTS_EVENT_PLAYING_START:                // 开始播放回调                Log.i(TAG, "onPlayBegin");                break;            case SpeechConstants.TTS_EVENT_PLAYING_END:                // 播放完成回调                Log.i(TAG, "onPlayEnd");                break;            case SpeechConstants.TTS_EVENT_PAUSE:                // 暂停回调                Log.i(TAG, "pause");                break;            case SpeechConstants.TTS_EVENT_RESUME:                // 恢复回调                Log.i(TAG, "resume");                break;            case SpeechConstants.TTS_EVENT_STOP:                // 停止回调                Log.i(TAG, "stop");                break;            case SpeechConstants.TTS_EVENT_RELEASE:                // 释放资源回调                Log.i(TAG, "release");                break;            default:                break;        }    }    @Override    public void onError(int type, String errorMSG) {        Log.e(TAG, "语音合成错误回调: " + errorMSG);    }    public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {        try {            InputStream is = context.getAssets().open(fileName);            FileOutputStream fos = new FileOutputStream(new File(path));            byte[] buffer = new byte[1024];            int byteCount = 0;            while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节                fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流            }            fos.flush();// 刷新缓冲区            is.close();            fos.close();        } catch (IOException e) {            Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());        }    }}


    同样的需要新建MyApplication.java进行预初始化离线语音合成功能
package com.cyf.ttsdemo;import android.app.Application;import android.content.Context;import com.cyf.ttsdemo.utils.TTSUtils;/** * Created by As on 2017/8/7. */public class MyApplication extends Application{    private static Context context;    @Override    public void onCreate() {        super.onCreate();        context = getApplicationContext();        TTSUtils.getInstance().init();    }    public static Context getContext(){        return context;    }}
    最后,别忘了在AndroidManifest.xml文件中注册该Application
    好的,这样就大功告成了,在需要进行语音合成的地方调用TTSUtils.getInstance().speak("xxx")即可
    注意:离线语音合成因为需要复制文件到SD卡中,所以初始化是比较耗时的,这就有可能造成有一些情况:初始化还未完成,但调用了语音合成方法没有声音的情况,而我在代码中并未处理,所以有遇到类似情况的,可以自己琢磨处理一下。

更多相关文章

  1. 跟我学Android应用开发 之 Android中资源文件的使用
  2. Android如果对APK进行加密,提高反编译难度(思路)
  3. Android(安卓)数据库文件 db 的备份和重载
  4. 将android工程作为另一个工程的库
  5. android二维码入库软件
  6. Android隐式启动Activity可能存在的坑
  7. android 4.0 兼容性问题 java.lang.NoSuchMethodError TextView.
  8. android 页面布局时定义控件ID时@id/XX和@+id/xx 有什么区别?
  9. 集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文

随机推荐

  1. android【打电话,收发短信实现】
  2. Android(安卓)Toast
  3. Android(安卓)球碰撞反弹 (2)
  4. android 检查可用网络
  5. android 6.0权限问题处理的核心代码--sho
  6. android JPushInterface.setAlias 报错 j
  7. Android实现“退出确认”对话框
  8. Android(安卓)Fresco的使用
  9. Android(安卓)检查是否安装SD卡
  10. android webview 中处理网页中的400、404