集成Android百度语音合成功能(在线、离线、离在线融合)

转至博客http://blog.csdn.net/aquarius_seven/article/details/76850292

    前面2篇文章分别写了在线和离线2种语音合成,分别用的是科大讯飞和云知声的SDK,那么本文就开始写离在线融合的百度语音SDK。

    你们知道吗,百度语音跟百度导航SDK有冲突,因为百度导航SDK内置了百度语音,但是它并没有暴露语音合成功能出来给我们调用,所以用了百度语音就用不了百度导航,用了百度导航就用不了百度语音,就是那么坑。

    没办法,项目要求一定要用百度的地图和导航,还要有语音合成功能,那么只能用百度语音的restAPI或者是选择其它的第三方SDK了,也就是我前面2篇文章的由来了,一开始我选择了讯飞的在线合成,后来发现有时候不太方便,又选择了云知声的离线合成。

    好吧,废话不多说,现在就开始集成吧。

首先,打开百度语音开放平台

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

打开应用管理,创建新应用-->选择服务(语音合成)-->下载SDK(语音合成)-->集成开发(补全包名)-->完成

下载完成,解压压缩包BaiduTtsSample

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

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

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


[html] view plain copy

  1. repositories {  
  2.     flatDir {  
  3.         dir 'libs'  
  4.     }  
  5. }  
 
  1. repositories {

  2. flatDir {

  3. dir 'libs'

  4. }

  5. }

[html] view plain copy

  1. sourceSets {  
  2.     main {  
  3.         jniLibs.srcDir 'libs'  
  4.     }  
  5. }  
 
  1. sourceSets {

  2. main {

  3. jniLibs.srcDir 'libs'

  4. }

  5. }

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

    首先,AndroidManifest.xml申请权限(6.0需要动态申请权限,碍于篇幅,请自行百度)

[html] view plain copy

  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
  3. <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />  
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  5. <uses-permission android:name="android.permission.WRITE_SETTINGS" />  
  6. <uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  7. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
  8. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />  
 
  1. <uses-permission android:name="android.permission.INTERNET" />

  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

  3. <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  5. <uses-permission android:name="android.permission.WRITE_SETTINGS" />

  6. <uses-permission android:name="android.permission.READ_PHONE_STATE" />

  7. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

  8. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    然后,直接封装成工具类,以供全局调用离在线语音合成功能,大家可以直接复制进去用,其中APIKEY、SECRETKEY和APPID在百度语音开放平台-->应用管理,点击你之前创建的应用可查看

[java] view plain copy

  1. package com.cyf.ttsdemo.utils;  
  2.   
  3. import android.content.Context;  
  4. import android.os.Environment;  
  5. import android.util.Log;  
  6.   
  7. import com.baidu.tts.client.SpeechError;  
  8. import com.baidu.tts.client.SpeechSynthesizer;  
  9. import com.baidu.tts.client.SpeechSynthesizerListener;  
  10. import com.baidu.tts.client.TtsMode;  
  11. import com.cyf.ttsdemo.MyApplication;  
  12.   
  13. import java.io.File;  
  14. import java.io.FileOutputStream;  
  15. import java.io.IOException;  
  16. import java.io.InputStream;  
  17.   
  18. /** 
  19.  * Created by As on 2017/8/7. 
  20.  */  
  21.   
  22. public class TTSUtils implements SpeechSynthesizerListener {  
  23.   
  24.     private static final String TAG = "TTSUtils";  
  25.     private static volatile TTSUtils instance = null;  
  26.     private SpeechSynthesizer mSpeechSynthesizer;  
  27.   
  28.     private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/baiduTTS/";  
  29.     private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat";  
  30.     private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";  
  31.   
  32.     private static final String APIKEY = "6kl3vrfNvLRo8iIWp93NRwkw";  
  33.     private static final String SECRETKEY = "ae9d2a7fb54ce8f2f80c46c22ca4acaf";  
  34.     private static final String APPID = "9978777";  
  35.   
  36.     private TTSUtils() {  
  37.     }  
  38.   
  39.     public static TTSUtils getInstance() {  
  40.         if (instance == null) {  
  41.             synchronized (TTSUtils.class) {  
  42.                 if (instance == null) {  
  43.                     instance = new TTSUtils();  
  44.                 }  
  45.             }  
  46.         }  
  47.         return instance;  
  48.     }  
  49.   
  50.     public void init() {  
  51.         Context context = MyApplication.getContext();  
  52.         File file = new File(SAMPLE_DIR);  
  53.         if (!file.exists()) {  
  54.             file.mkdirs();  
  55.         }  
  56.         File textModelFile = new File(SAMPLE_DIR + TEXT_MODEL_NAME);  
  57.         if (!textModelFile.exists()) {  
  58.             copyAssetsFile2SDCard(context, TEXT_MODEL_NAME, SAMPLE_DIR + TEXT_MODEL_NAME);  
  59.         }  
  60.         File speechModelFile = new File(SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);  
  61.         if (!speechModelFile.exists()) {  
  62.             copyAssetsFile2SDCard(context, SPEECH_FEMALE_MODEL_NAME, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);  
  63.         }  
  64.         // 获取语音合成对象实例  
  65.         mSpeechSynthesizer = SpeechSynthesizer.getInstance();  
  66.         // 设置context  
  67.         mSpeechSynthesizer.setContext(context);  
  68.         // 设置语音合成状态监听器  
  69.         mSpeechSynthesizer.setSpeechSynthesizerListener(this);  
  70.         mSpeechSynthesizer.setApiKey(APIKEY, SECRETKEY);  
  71.         // 设置离线语音合成授权,需要填入从百度语音官网申请的app_id  
  72.         mSpeechSynthesizer.setAppId(APPID);  
  73.         // 设置语音合成文本模型文件  
  74.         mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, SAMPLE_DIR + TEXT_MODEL_NAME);  
  75.         // 设置语音合成声音模型文件  
  76.         mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);  
  77.         // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)  
  78.         mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");  
  79.         // 设置Mix模式的合成策略  
  80.         mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);  
  81.         // 初始化tts  
  82.         mSpeechSynthesizer.initTts(TtsMode.MIX);  
  83.     }  
  84.   
  85.     //需要合成的msg长度不能超过1024个GBK字节。  
  86.     public void speak(String msg) {  
  87.         int result = mSpeechSynthesizer.speak(msg);  
  88.         if (result < 0) {  
  89.             Log.e(TAG, "error,please look up error code = " + result + " in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");  
  90.         }  
  91.     }  
  92.   
  93.     public void pause() {  
  94.         mSpeechSynthesizer.pause();  
  95.     }  
  96.   
  97.     public void resume() {  
  98.         mSpeechSynthesizer.resume();  
  99.     }  
  100.   
  101.     public void stop() {  
  102.         mSpeechSynthesizer.stop();  
  103.     }  
  104.   
  105.     public void release() {  
  106.         if (null != mSpeechSynthesizer) {  
  107.             mSpeechSynthesizer.release();  
  108.         }  
  109.     }  
  110.   
  111.     @Override  
  112.     public void onSynthesizeStart(String s) {  
  113.         // 监听到合成开始,在此添加相关操作  
  114.     }  
  115.   
  116.     @Override  
  117.     public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {  
  118.         // 监听到有合成数据到达,在此添加相关操作  
  119.     }  
  120.   
  121.     @Override  
  122.     public void onSynthesizeFinish(String s) {  
  123.         // 监听到合成结束,在此添加相关操作  
  124.     }  
  125.   
  126.     @Override  
  127.     public void onSpeechStart(String s) {  
  128.         // 监听到合成并播放开始,在此添加相关操作  
  129.     }  
  130.   
  131.     @Override  
  132.     public void onSpeechProgressChanged(String s, int i) {  
  133.         // 监听到播放进度有变化,在此添加相关操作  
  134.     }  
  135.   
  136.     @Override  
  137.     public void onSpeechFinish(String s) {  
  138.         // 监听到播放结束,在此添加相关操作  
  139.     }  
  140.   
  141.     @Override  
  142.     public void onError(String s, SpeechError speechError) {  
  143.         // 监听到出错,在此添加相关操作  
  144.     }  
  145.   
  146.     public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {  
  147.         try {  
  148.             InputStream is = context.getAssets().open(fileName);  
  149.             FileOutputStream fos = new FileOutputStream(new File(path));  
  150.             byte[] buffer = new byte[1024];  
  151.             int byteCount = 0;  
  152.             while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节  
  153.                 fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流  
  154.             }  
  155.             fos.flush();// 刷新缓冲区  
  156.             is.close();  
  157.             fos.close();  
  158.         } catch (IOException e) {  
  159.             Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());  
  160.         }  
  161.     }  
  162. }<span style="font-size: 14px; font-family: "Microsoft YaHei";">  
  163. </span>  
 
  1. package com.cyf.ttsdemo.utils;

  2.  
  3. import android.content.Context;

  4. import android.os.Environment;

  5. import android.util.Log;

  6.  
  7. import com.baidu.tts.client.SpeechError;

  8. import com.baidu.tts.client.SpeechSynthesizer;

  9. import com.baidu.tts.client.SpeechSynthesizerListener;

  10. import com.baidu.tts.client.TtsMode;

  11. import com.cyf.ttsdemo.MyApplication;

  12.  
  13. import java.io.File;

  14. import java.io.FileOutputStream;

  15. import java.io.IOException;

  16. import java.io.InputStream;

  17.  
  18. /**

  19. * Created by As on 2017/8/7.

  20. */

  21.  
  22. public class TTSUtils implements SpeechSynthesizerListener {

  23.  
  24. private static final String TAG = "TTSUtils";

  25. private static volatile TTSUtils instance = null;

  26. private SpeechSynthesizer mSpeechSynthesizer;

  27.  
  28. private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/baiduTTS/";

  29. private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat";

  30. private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";

  31.  
  32. private static final String APIKEY = "6kl3vrfNvLRo8iIWp93NRwkw";

  33. private static final String SECRETKEY = "ae9d2a7fb54ce8f2f80c46c22ca4acaf";

  34. private static final String APPID = "9978777";

  35.  
  36. private TTSUtils() {

  37. }

  38.  
  39. public static TTSUtils getInstance() {

  40. if (instance == null) {

  41. synchronized (TTSUtils.class) {

  42. if (instance == null) {

  43. instance = new TTSUtils();

  44. }

  45. }

  46. }

  47. return instance;

  48. }

  49.  
  50. public void init() {

  51. Context context = MyApplication.getContext();

  52. File file = new File(SAMPLE_DIR);

  53. if (!file.exists()) {

  54. file.mkdirs();

  55. }

  56. File textModelFile = new File(SAMPLE_DIR + TEXT_MODEL_NAME);

  57. if (!textModelFile.exists()) {

  58. copyAssetsFile2SDCard(context, TEXT_MODEL_NAME, SAMPLE_DIR + TEXT_MODEL_NAME);

  59. }

  60. File speechModelFile = new File(SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);

  61. if (!speechModelFile.exists()) {

  62. copyAssetsFile2SDCard(context, SPEECH_FEMALE_MODEL_NAME, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);

  63. }

  64. // 获取语音合成对象实例

  65. mSpeechSynthesizer = SpeechSynthesizer.getInstance();

  66. // 设置context

  67. mSpeechSynthesizer.setContext(context);

  68. // 设置语音合成状态监听器

  69. mSpeechSynthesizer.setSpeechSynthesizerListener(this);

  70. mSpeechSynthesizer.setApiKey(APIKEY, SECRETKEY);

  71. // 设置离线语音合成授权,需要填入从百度语音官网申请的app_id

  72. mSpeechSynthesizer.setAppId(APPID);

  73. // 设置语音合成文本模型文件

  74. mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, SAMPLE_DIR + TEXT_MODEL_NAME);

  75. // 设置语音合成声音模型文件

  76. mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);

  77. // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)

  78. mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");

  79. // 设置Mix模式的合成策略

  80. mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);

  81. // 初始化tts

  82. mSpeechSynthesizer.initTts(TtsMode.MIX);

  83. }

  84.  
  85. //需要合成的msg长度不能超过1024个GBK字节。

  86. public void speak(String msg) {

  87. int result = mSpeechSynthesizer.speak(msg);

  88. if (result < 0) {

  89. Log.e(TAG, "error,please look up error code = " + result + " in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");

  90. }

  91. }

  92.  
  93. public void pause() {

  94. mSpeechSynthesizer.pause();

  95. }

  96.  
  97. public void resume() {

  98. mSpeechSynthesizer.resume();

  99. }

  100.  
  101. public void stop() {

  102. mSpeechSynthesizer.stop();

  103. }

  104.  
  105. public void release() {

  106. if (null != mSpeechSynthesizer) {

  107. mSpeechSynthesizer.release();

  108. }

  109. }

  110.  
  111. @Override

  112. public void onSynthesizeStart(String s) {

  113. // 监听到合成开始,在此添加相关操作

  114. }

  115.  
  116. @Override

  117. public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {

  118. // 监听到有合成数据到达,在此添加相关操作

  119. }

  120.  
  121. @Override

  122. public void onSynthesizeFinish(String s) {

  123. // 监听到合成结束,在此添加相关操作

  124. }

  125.  
  126. @Override

  127. public void onSpeechStart(String s) {

  128. // 监听到合成并播放开始,在此添加相关操作

  129. }

  130.  
  131. @Override

  132. public void onSpeechProgressChanged(String s, int i) {

  133. // 监听到播放进度有变化,在此添加相关操作

  134. }

  135.  
  136. @Override

  137. public void onSpeechFinish(String s) {

  138. // 监听到播放结束,在此添加相关操作

  139. }

  140.  
  141. @Override

  142. public void onError(String s, SpeechError speechError) {

  143. // 监听到出错,在此添加相关操作

  144. }

  145.  
  146. public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {

  147. try {

  148. InputStream is = context.getAssets().open(fileName);

  149. FileOutputStream fos = new FileOutputStream(new File(path));

  150. byte[] buffer = new byte[1024];

  151. int byteCount = 0;

  152. while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节

  153. fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流

  154. }

  155. fos.flush();// 刷新缓冲区

  156. is.close();

  157. fos.close();

  158. } catch (IOException e) {

  159. Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());

  160. }

  161. }

  162. }

  163.  

    同样的需要新建MyApplication.java进行预初始化离线语音合成功能
[java] view plain copy

  1. package com.cyf.ttsdemo;  
  2.   
  3. import android.app.Application;  
  4. import android.content.Context;  
  5.   
  6. import com.cyf.ttsdemo.utils.TTSUtils;  
  7.   
  8. /** 
  9.  * Created by As on 2017/8/7. 
  10.  */  
  11.   
  12. public class MyApplication extends Application {  
  13.   
  14.     private static Context context;  
  15.   
  16.     @Override  
  17.     public void onCreate() {  
  18.         super.onCreate();  
  19.         context = getApplicationContext();  
  20.         TTSUtils.getInstance().init();  
  21.     }  
  22.   
  23.     public static Context getContext() {  
  24.         return context;  
  25.     }  
  26. }<span style="font-size: 14px; font-family: "Microsoft YaHei";">  
  27. </span>  
 
  1. package com.cyf.ttsdemo;

  2.  
  3. import android.app.Application;

  4. import android.content.Context;

  5.  
  6. import com.cyf.ttsdemo.utils.TTSUtils;

  7.  
  8. /**

  9. * Created by As on 2017/8/7.

  10. */

  11.  
  12. public class MyApplication extends Application {

  13.  
  14. private static Context context;

  15.  
  16. @Override

  17. public void onCreate() {

  18. super.onCreate();

  19. context = getApplicationContext();

  20. TTSUtils.getInstance().init();

  21. }

  22.  
  23. public static Context getContext() {

  24. return context;

  25. }

  26. }

  27.  

    最后,别忘了在AndroidManifest.xml文件中注册该Application

    好的,这样就大功告成了,在需要进行语音合成的地方调用TTSUtils.getInstance().speak("xxx")即可

    最后,我们需要到百度语音开放平台进行申请提高配额,不然使用的语音合成功能每天是有次数限制的。

    当应用审核通过之后,就可以免费无限制的使用离在线语音合成功能啦。

猜你喜欢

转载自blog.csdn.net/IT666DHW/article/details/81910580