百度语音SDK使用
百度语音SDK提供:语音识别:将声音转成文字语音合成:将文字转成语音文件,然后播放语音文件,即文字变声音。语音唤醒:语音唤醒,激活运用程序
百度语音SDK提供:
语音识别:将声音转成文字
语音合成:将文字转成语音文件,然后播放语音文件,即文字变声音。
语音唤醒:语音唤醒,激活运用程序
在这里,本篇介绍百度语音合成的使用。
百度语音介绍:
- 永久免费
- 多语言(中文,中英混读)多音色(男音,女音)可选
- 离线与在线,节省流量
详情参考,百度语音介绍
百度语音使用流程指南:
- 成为开发者,创建运用,选择服务
- 下载对应的SDK,集成开发。
项目集成百度语音SDK:
在androidStudio中按照其AS特有的使用方式添加添加so库,相关的jar。
添加完so库,jar库后,需Gradle中配置如下:
android { ........ sourceSets { main { //设置so库依赖路径 jniLibs.srcDirs = ['libs'] } } } dependencies { ..... compile files('libs/com.baidu.tts_2.3.0.jar') }
在androidStudio中assert文件夹下添加文本模型文件.dat,和声音模型文件.dat(无网络,离线下使用的)。这里因项目需求,只添加下载到女生模型文件。
添加以下权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
Proguard配置(不需要混淆sdk中jar包)
编写相关使用代码如下:
5.1 加载离线资源,先创建存储的文件夹,然后将assert中模型文件一个个通过Stream读写(异步操作,可考虑工作线程或者RxJava完成)指定的文件夹下:
/** * 百度tts文件夹 */ public static final String BAIDU_TTS_DIR_NAME = "baiduTts"; public static final String SPEECH_FEMALE_MODE_NAME = "bd_etts_ch_speech_female.dat"; public static final String TEXT_MODEL_NAME = "bd_etts_ch_text.dat"; /** * 初始化语音文件的配置 * * @param context */ private void initFileConfig(Context context) { File dirFile = getDirFile(context); if (dirFile != null && !dirFile.exists()) { dirFile.mkdir(); copyFromAssertsToSDCard(context, SPEECH_FEMALE_MODE_NAME, getFilePath(dirFile, SPEECH_FEMALE_MODE_NAME)); copyFromAssertsToSDCard(context, TEXT_MODEL_NAME, getFilePath(dirFile, TEXT_MODEL_NAME)); } } /** * 获取目录 * * @param context * @return */ public File getDirFile(Context context) { return MyUtils.getCacheFile(context, BAIDU_TTS_DIR_NAME); } /** * 获取文件路径 * * @param dirFile * @param fileName * @return */ public String getFilePath(File dirFile, String fileName) { return dirFile.getAbsolutePath() + File.separator + fileName; } /** * 将文件写入sdcard中 * * @param context * @param assertFileName * @param filePath */ private void copyFromAssertsToSDCard(Context context, String assertFileName, String filePath) { FileOutputStream outputStream = null; InputStream inputStream = null; try { inputStream = context.getResources().getAssets().open(assertFileName); outputStream = new FileOutputStream(filePath); byte[] buffer = new byte[1024]; int length = 0; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } } catch (Exception e) { e.printStackTrace(); } } }
MyUtil工具类中创建文件夹的代码如下:
/** * 获得存储文件 * * @param * @param * @return */ public static File getCacheFile(Context context,String name) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + name); }
5.2 配置语音合成客户端:
/** * 运用的配置信息,由百度语音官网给定 */ public static final String API_KEY = "hBuMkBgzGR0YQQHflkufAWcvFRaqTxxx"; public static final String SECRET_KEY = "FemUYlEKxzr0moQ0jydZcmQ3fo11xxx"; public static final String APP_ID = "9369xxx"; /** * 语音合成的客户端 */ private SpeechSynthesizer speechSynthesizer; /** * 合成状态的监听器 */ private SpeechSynthesizerListener speechSynthesizerListener; /** * 初始化语音的client */ private void initBaiduTts(Context context) { speechSynthesizer = SpeechSynthesizer.getInstance(); speechSynthesizer.setContext(context); //设置监听器 if (getSpeechSynthesizerListener() != null) { speechSynthesizer.setSpeechSynthesizerListener(getSpeechSynthesizerListener()); } //设置运用的api_key和secret_key speechSynthesizer.setApiKey(API_KEY, SECRET_KEY); //设置运用的app_id speechSynthesizer.setAppId(APP_ID); File dirFile = getDirFile(context); //设置语音合成中文本模型文件(离线使用) speechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, getFilePath(dirFile, TEXT_MODEL_NAME)); //设置语音合成中声音模型文件(离线使用) speechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, getFilePath(dirFile, SPEECH_FEMALE_MODE_NAME)); //发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。) speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0"); //设置Mix模式的合成策略 speechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT); //上线的时候,移除授权检查操作,即移除以下if语句 if (isAuthSuccess()) { LogController.i(BaiduTtsController.class.getSimpleName(), "首次验证成功"); } //初始化tts speechSynthesizer.initTts(TtsMode.MIX); } /** * 用于首次使用的使用,测试检查运用是成功申请到授权。注意点:若是测试无误后,可省略该步骤。 * * @return */ public boolean isAuthSuccess() { AuthInfo info = speechSynthesizer.auth(TtsMode.MIX); if (!info.isSuccess()) { LogController.i(BaiduTtsController.class.getSimpleName(), "错误信息: " + info.getTtsError().getMessage()); } return info.isSuccess(); } public SpeechSynthesizerListener getSpeechSynthesizerListener() { return speechSynthesizerListener; } /** * 设置语音合成的监听器 * * @param speechSynthesizerListener */ public void setSpeechSynthesizerListener(SpeechSynthesizerListener speechSynthesizerListener) { this.speechSynthesizerListener = speechSynthesizerListener; if(speechSynthesizerListener!=null){ this.speechSynthesizer.setSpeechSynthesizerListener(this.speechSynthesizerListener); } }
5.3 语音合成客户端的生命周期管理:
在Activity或者Service的生命周期中使用,onCreate()调用客户端的初始化操作(即以上两个配置步骤), onResume()调用客户端的resume(),Onstop()中调用客户端的stop().最后在onDestory()中调用客户端的release()
/** * 释放资源 */ public void release() { this.speechSynthesizer.release(); } /** * 停止正在执行的任务 */ public void stop() { this.speechSynthesizer.stop(); } /** * 恢复暂停的任务 */ public void resume() { this.speechSynthesizer.resume(); }
5.4 通过语音合成的客户端,将多段文本按一定顺序或者单独一段文本进行播放:
/** * 将text转成一个语音文件,然后自动播放。 * * * @param text */ public void speeckText(String text) { if (!TextUtils.isEmpty(text)) { this.speechSynthesizer.speak(text); } } /** * 有顺序的合成多段语音,然后按一定顺序播放。 * * @param values */ public void speeckTextValues(String[] values) { if (values == null && values.length == 0) { return; } List<SpeechSynthesizeBag> bags = new ArrayList<>(); for (int i = 0; i < values.length; ++i) { bags.add(getSpeechSynthesizeBag(values[i], String.valueOf(i))); } this.speechSynthesizer.batchSpeak(bags); } /** * * @param text 播放的文本内容 * @param utterancedId 播放顺序,即第几个播放 * @return */ private SpeechSynthesizeBag getSpeechSynthesizeBag(String text, String utterancedId) { SpeechSynthesizeBag speechSynthesizeBag = new SpeechSynthesizeBag(); //需要合成的文本text的长度不能超过1024个GBK字节。 speechSynthesizeBag.setText(text); speechSynthesizeBag.setUtteranceId(utterancedId); return speechSynthesizeBag; }
5.5 监控语音合成客户端的监听器(即SpeechSynthesizerListener)
public class MessageDialogActivity extends BaseActivity implements View.OnClickListener,SpeechSynthesizerListener { private static final String TAG=MessageDialogActivity.class.getSimpleName(); @Override public void onSynthesizeStart(String s) { LogController.i(TAG," onSynthesizeStart "+s); } @Override public void onSynthesizeDataArrived(String s, byte[] bytes, int i) { LogController.i(TAG," onSynthesizeDataArrived "+s); } @Override public void onSynthesizeFinish(String s) { LogController.i(TAG," onSynthesizeFinish "+s); } @Override public void onSpeechStart(String s) { LogController.i(TAG," onSpeechStart "+s); } @Override public void onSpeechProgressChanged(String s, int i) { LogController.i(TAG," onSpeechProgressChanged "+s); } @Override public void onSpeechFinish(String s) { LogController.i(TAG," onSpeechFinish "+s); } @Override public void onError(String s, SpeechError speechError) { LogController.i(TAG," onError "+speechError.description); } }
(个人)在实际项目中做法:
将百度语音客户端的初始化操作,生命周期管理操作,播放语音操作,封装成一个操作类。
public class BaiduTtsController { public static BaiduTtsController instance; private BaiduTtsController(Context context) { initConfig(context); } public synchronized static BaiduTtsController getInstance(Context context) { return instance = instance == null ? new BaiduTtsController(context) : instance; } public void initConfig(Context context) { initFileConfig(context); initBaiduTts(context); } //剩下的是,初始化,生命周期,播放的具体代码,以上步骤已经贴出。 }
将这个操作类保存到自定义的Application子类中,作为一个全局共享的对象。
public class BaseApplication extends Application { private BaiduTtsController controller; public BaiduTtsController initBaiduTts(){ return controller= controller==null?BaiduTtsController.getInstance(this):controller; } public BaiduTtsController getBaiduTtsController(){ return controller; } public void setBaiduTtsController(BaiduTtsController controller){ this.controller=controller; } }
在service中通过Application子类对象,获取到操作类对象,拿到需要播放的文本,调用播放语音的操作。
private BaiduTtsController controller; //获取操作类的对象 controller=BaseApplication.getAppContext().getBaiduTtsController(); controller.setSpeechSynthesizerListener(this); //播放文本 controller.speeckText(msg1);
开发遇到问题:
- so库没有加载成功,控制台日志如下:
No implementation found for int com.baidu.tts.jni.EmbeddedSynthesizerEngine.bdTTSGetLicense
No implementation found for int com.baidu.speechsynthesizer.utility.SpeechDecoder.decodeWithCallback
解决方式:正确导入so库,可以在手机中安装的运用查看so库是否随运用一起安装在手机上。
运用的签名错误,控制台日志如下:
Authentication Error ============================================= ----------------- 鉴权错误信息 ------------ sha1;package:B3:88:6A:66:18:70:4E:FE:48:60:4C:4C:37:A9:2D:84:5D:16:56:xx;com.xxx.mjqzclient key:RWpAlKWQE8SBoE354xUYeRcy906Asxxx errorcode: -11 uid: -1 appid -1 msg: httpsPost failed,IOException:Unable to resolve host "api.map.baidu.com": No address associated with hostname 请仔细核查 SHA1、package与key申请信息是否对应,key是否删除,平台是否匹配 errorcode为230时,请参考论坛链接: http://bbs.lbsyun.baidu.com/forum.php?mod=viewthread&tid=106461
解决方式:正确配置App的签名,然后在开发平台上,填写对应的包名,和sha1值。
更多推荐
所有评论(0)