注册
使用灵云的语音合成功能需要先在官网上进行注册应用。官网地址
注册比较简单,就不做过多介绍了,注册完应用以后,在后台创建自己的应用,创建完应用以后需要给应用开通对应的语音能力。
capKey说明:
- tts.cloud.wangjing对应的使在线合成功能
- tts.local.synth对应的是离线合成功能
- tts.local.synth.sing对应的是离线歌唱功能
集成
下载灵云的Android版本语音合成功能,下载地址
如果使用在线功能,下载对应的SDK,里面有jar包和so,就可以满足需求了。如果要使用离线的语音功能,还需要下载灵云资源文件
源码
灵云在线合成功能
需要加入的so和jar包有:
- libhci_curl.so
- libhci_sys.so
- libhci_sys_jni.so
- libhci_tts.so
- libhci_tts_jni.so
- libhci_tts_cloud.synth.so
- libspeex.so
- libstlport_shared.so
- hcicloud-5.0.jar
- hcicloud_player-5.0.jar
权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
配置类
package com.example.sinovoice.util;
/**
* 灵云配置信息
* Created by 10048 on 2016/12/3.
*/
public class ConfigUtil {
/**
* 灵云APP_KEY
*/
public static final String APP_KEY = "c85d54f1";
/**
* 开发者密钥
*/
public static final String DEVELOPER_KEY = "712ddd892cf9163e6383aa169e0454e3";
/**
* 灵云云服务的接口地址
*/
public static final String CLOUD_URL = "test.api.hcicloud.com:8888";
/**
* 需要运行的灵云能力
*/
// 离线语音合成
public static final String CAP_KEY_TTS_LOCAL = "tts.local.synth";
//离线歌唱合成功能
public static final String CAP_KEY_TTS_LOCAL_SING = "tts.local.synth.sing";
// 云端语音合成
public static final String CAP_KEY_TTS_CLOUD = "tts.cloud.wangjing";
}
封装灵云系统的初始化功能
package com.example.sinovoice.util;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Created by miaochangchun on 2016/11/28.
*/
public class HciCloudSysHelper {
private static final String TAG = HciCloudSysHelper.class.getSimpleName();
private static HciCloudSysHelper mHciCloudSysHelper = null;
private HciCloudSysHelper(){
}
public static HciCloudSysHelper getInstance() {
if (mHciCloudSysHelper == null) {
return new HciCloudSysHelper();
}
return mHciCloudSysHelper;
}
/**
* 初始化函数
* @param context
* @return
*/
public int init(Context context){
//配置串参数
String strConfig = getInitParam(context);
int errCode = HciCloudSys.hciInit(strConfig, context);
if (errCode != HciErrorCode.HCI_ERR_NONE){
Log.e(TAG, "hciInit Failed and return errcode = " + errCode);
return errCode;
}
errCode = checkAuthAndUpdateAuth();
if (errCode != HciErrorCode.HCI_ERR_NONE) {
Log.e(TAG, "checkAuthAndUpdateAuth Failed and return errcode = " + errCode);
return errCode;
}
return HciErrorCode.HCI_ERR_NONE;
}
/**
* 获取授权
* @return
*/
private int checkAuthAndUpdateAuth() {
// 获取系统授权到期时间
AuthExpireTime objExpireTime = new AuthExpireTime();
int initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
if (initResult == HciErrorCode.HCI_ERR_NONE) {
// 显示授权日期,如用户不需要关注该值,此处代码可忽略
Date date = new Date(objExpireTime.getExpireTime() * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
Log.i(TAG, "expire time: " + sdf.format(date));
if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
// 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
Log.i(TAG, "checkAuth success");
return initResult;
}
}
// 获取过期时间失败或者已经过期
initResult = HciCloudSys.hciCheckAuth();
if (initResult == HciErrorCode.HCI_ERR_NONE) {
Log.i(TAG, "checkAuth success");
return initResult;
} else {
Log.e(TAG, "checkAuth failed: " + initResult);
return initResult;
}
}
/**
* 获取配置传参数
* @param context
* @return
*/
private String getInitParam(Context context) {
InitParam initParam = new InitParam();
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);
String authPath = context.getFilesDir().getAbsolutePath();
//授权文件所在路径,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authPath);
//日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
String logPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
+ "sinovoice" + File.separator
+ context.getPackageName() + File.separator
+ "log" + File.separator;
File file = new File(logPath);
if (!file.exists()) {
file.mkdirs();
}
//日志的路径,可选,如果不传或者为空则不生成日志
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
Log.d(TAG, "logPath = " + logPath);
//日志大小,默认一个日志文件写多大,单位为K
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
//日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
return initParam.getStringConfig();
}
/**
* 反初始化
* @return
*/
public int release(){
return HciCloudSys.hciRelease();
}
}
封装灵云语音合成功能
package com.example.sinovoice.util;
import android.content.Context;
import android.util.Log;
import com.sinovoice.hcicloudsdk.android.tts.player.TTSPlayer;
import com.sinovoice.hcicloudsdk.common.tts.TtsConfig;
import com.sinovoice.hcicloudsdk.common.tts.TtsInitParam;
import com.sinovoice.hcicloudsdk.player.TTSCommonPlayer;
import com.sinovoice.hcicloudsdk.player.TTSPlayerListener;
/**
* Created by miaochangchun on 2016/11/28.
*/
public class HciCloudTtsHelper {
private static final String TAG = HciCloudTtsHelper.class.getSimpleName();
private static HciCloudTtsHelper mHciCloudTtsHelper = null;
private TTSPlayer mTtsPlayer;
private HciCloudTtsHelper(){
}
/**
* 获取初始化对象
* @return
*/
public static HciCloudTtsHelper getInstance() {
if (mHciCloudTtsHelper == null) {
return new HciCloudTtsHelper();
}
return mHciCloudTtsHelper;
}
/**
* 播放器初始化
* @param context 上下文
* @param initCapkeys 需要初始化的capkey,可以设置为多个,中间以;间隔
* @return true播放器初始化成功,false初始化失败
*/
public boolean initTtsPlayer(Context context, String initCapkeys){
mTtsPlayer = new TTSPlayer();
String strConfig = getTtsInitParam(context, initCapkeys);
mTtsPlayer.init(strConfig, new TTSEventProcess());
//设置使用AudioFocus机制
mTtsPlayer.setContext(context);
//mTtsPlayer.setPlayerRouteFlag(0); 可以再次设置播放器的通道
Log.d(TAG, "initTtsPlayer Success.");
if (mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_IDLE) {
return true;
} else {
return false;
}
}
/**
* 开始播放
* @param text 需要播放的文本
* @param capkey 发音人选择
*/
public void playTtsPlayer(String text, String capkey) {
String strConfig = getTtsSynthConfig(capkey);
Log.d(TAG, "mTtsPlayer = " + mTtsPlayer);
if (mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_PLAYING || mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_PAUSE) {
mTtsPlayer.stop();
}
if (mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_IDLE) {
mTtsPlayer.play(text, strConfig);
}
}
/**
* 暂停播放
*/
public void pauseTtsPlayer(){
if (mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_PLAYING) {
mTtsPlayer.pause();
}
}
/**
* 恢复播放
*/
public void resumeTtsPlayer(){
if (mTtsPlayer.getPlayerState() == TTSCommonPlayer.PLAYER_STATE_PAUSE) {
mTtsPlayer.resume();
}
}
/**
* 停止播放
*/
public void stopTtsPlayer(){
if (mTtsPlayer.canStop()){
mTtsPlayer.stop();
}
}
/**
* 公有云配置参数
* @param capkey
* @return
*/
private String getTtsSynthConfig(String capkey) {
TtsConfig ttsConfig = new TtsConfig();
ttsConfig.addParam(TtsConfig.SessionConfig.PARAM_KEY_CAP_KEY, capkey);
ttsConfig.addParam(TtsConfig.BasicConfig.PARAM_KEY_AUDIO_FORMAT, "pcm16k16bit");
ttsConfig.addParam(TtsConfig.BasicConfig.PARAM_KEY_SPEED, "5");
ttsConfig.addParam(TtsConfig.EncodeConfig.PARAM_KEY_ENCODE, "speex");
return ttsConfig.getStringConfig();
}
/**
* 获取TTS的参数配置
* @param context
* @param capkey 发音人
* @return
*/
private String getTtsInitParam(Context context, String capkey) {
TtsInitParam ttsInitParam = new TtsInitParam();
String dataPath = context.getFilesDir().getAbsolutePath().replace("files", "lib");
ttsInitParam.addParam(TtsInitParam.PARAM_KEY_DATA_PATH, dataPath);
ttsInitParam.addParam(TtsInitParam.PARAM_KEY_FILE_FLAG, "android_so");
ttsInitParam.addParam(TtsInitParam.PARAM_KEY_INIT_CAP_KEYS, capkey);
return ttsInitParam.getStringConfig();
}
/**
* 播放器反初始化
*/
public void releaseTtsPlayer(){
if (mTtsPlayer != null) {
mTtsPlayer.release();
}
}
/**
* 播放器回调类
*/
private class TTSEventProcess implements TTSPlayerListener {
/**
* 播放器的状态回调
* @param playerEvent
*/
@Override
public void onPlayerEventStateChange(TTSCommonPlayer.PlayerEvent playerEvent) {
}
/**
* 播放器播放进度回调
* @param playerEvent
* @param i
* @param i1
*/
@Override
public void onPlayerEventProgressChange(TTSCommonPlayer.PlayerEvent playerEvent, int i, int i1) {
}
/**
* 播放器的错误回调
* @param playerEvent
* @param i
*/
@Override
public void onPlayerEventPlayerError(TTSCommonPlayer.PlayerEvent playerEvent, int i) {
}
}
}
在MainActivity中使用
/**
* 灵云系统和tts功能初始化
*/
private void initSinovoice() {
mHciCloudSysHelper = HciCloudSysHelper.getInstance();
mHciCloudTtsHelper = HciCloudTtsHelper.getInstance();
int errorCode = mHciCloudSysHelper.init(this);
if (errorCode != HciErrorCode.HCI_ERR_NONE) {
Toast.makeText(this, "系统初始化失败,错误码=" + errorCode, Toast.LENGTH_SHORT).show();
return;
}
boolean bool = mHciCloudTtsHelper.initTtsPlayer(this, ConfigUtil.CAP_KEY_TTS_LOCAL);
if (bool == false) {
Toast.makeText(this, "播放器初始化失败", Toast.LENGTH_SHORT).show();
}
}
语音合成响应按钮事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_pause: //暂停播放
mHciCloudTtsHelper.pauseTtsPlayer();
break;
case R.id.btn_play: //开始播放
mHciCloudTtsHelper.playTtsPlayer(etText.getText().toString(), ConfigUtil.CAP_KEY_TTS_LOCAL);
break;
case R.id.btn_resume: //恢复播放
mHciCloudTtsHelper.resumeTtsPlayer();
break;
case R.id.btn_stop: //停止播放
mHciCloudTtsHelper.stopTtsPlayer();
break;
default:
break;
}
}
语音合成回调
/**
* 播放器回调类
*/
private class TTSEventProcess implements TTSPlayerListener {
/**
* 播放器的状态回调
* @param playerEvent
*/
@Override
public void onPlayerEventStateChange(TTSCommonPlayer.PlayerEvent playerEvent) {
}
/**
* 播放器播放进度回调
* @param playerEvent
* @param i
* @param i1
*/
@Override
public void onPlayerEventProgressChange(TTSCommonPlayer.PlayerEvent playerEvent, int i, int i1) {
}
/**
* 播放器的错误回调
* @param playerEvent
* @param i
*/
@Override
public void onPlayerEventPlayerError(TTSCommonPlayer.PlayerEvent playerEvent, int i) {
}
}
灵云离线合成功能
使用离线功能需要导入以下so库文件和jar包
- libhci_curl.so
- libhci_sys.so
- libhci_sys_jni.so
- libhci_tts.so
- libhci_tts_jni.so
- libhci_tts_local.synth.so
- libstlport_shared.so
- libCNPackage.dat.so
- libENPackage.dat.so
- libDMPackage.dat.so
- libDefault.conf.so
- hcicloud-5.0.jar
- hcicloud_player-5.0.jar
离线语音合成相对也比较简单,首先要下载离线资源,下载完以后是一个zip包,解压缩里面有类似这样的几个文件
给每个文件重命名,前面加lib
,后面加后缀.so
,然后导入工程
导入资源文件以后,修改capKey为离线语音合成
public static final String CAP_KEY = "tts.local.synth";
注:灵云的离线语音能力,第一次使用的时候也是需要有一个联网授权的过程,授权成功以后,即可在授权期内使用离线语音能力。