流式文本在线合成JAVA SDK
快速入门
安装Speech Java SDK
Speech Java SDK目录结构
1com.baidu.aip
2 ├── auth //签名相关类
3 ├── http //Http通信相关类
4 ├── client //公用类
5 ├── exception //exception类
6 ├── speech
7 │ └── AipSpeech //AipSpeech类
8 └── util //工具类
支持 JAVA版本:1.7+
查看源码
Java SDK代码现已公开,您可以查看代码、或者在License范围内修改和编译SDK以适配您的环境。请点击此处下载java sdk源代码。
使用maven依赖:
添加以下依赖即可。其中版本号可在maven官网查询
1<dependency>
2 <groupId>com.baidu.aip</groupId>
3 <artifactId>java-sdk</artifactId>
4 <version>${version}</version>
5</dependency>
直接使用JAR包步骤如下:
1.在官方网站下载识别、合成 RESTful API Java SDK压缩工具包。
2.将下载的aip-java-sdk-version.zip解压后,复制到工程文件夹中。
3.在Eclipse右键“工程 -> Properties -> Java Build Path -> Add JARs”。
4.添加SDK工具包aip-java-sdk-version.jar和第三方依赖工具包json-20160810.jar log4j-1.2.17.jar。
其中,version为版本号,添加完成后,用户就可以在工程中使用Speech Java SDK。
新建AipSpeech
AipSpeech是语音识别的Java客户端,为使用语音识别的开发人员提供了一系列的交互方法。
用户可以参考如下代码新建一个AipSpeech,初始化完成后建议单例使用,避免重复获取access_token:
1public class StreamTtsExample {
2 // 设置APPID/AK/SK
3 public static final String APP_ID = "你的 App ID";
4 public static final String API_KEY = "你的 Api Key";
5 public static final String SECRET_KEY = "你的 Secret Key";
6 private static final Logger LOGGER = LoggerFactory.getLogger(StreamTtsExample.class);
7
8 public static void main(String[] args) {
9 // 初始化一个AipSpeech
10 AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
11
12 // 可选:设置网络连接参数
13 client.setConnectionTimeoutInMillis(2000);
14 client.setSocketTimeoutInMillis(60000);
15
16 // 调用流式合成接口
17 StreamTtsSynthesis(client);
18 }
19
20 private static void StreamTtsSynthesis(AipSpeech client) {
21 // 创建请求参数
22 StreamTtsRequest request = new StreamTtsRequest();
23 request.setSpd(5); // 语速,取值0-15,默认为5中语速
24 request.setPit(5); // 音调,取值0-15,默认为5中语调
25 request.setVol(5); // 音量,取值0-15,默认为5中音量
26 request.setPer(4146); // 发音人选择, 4146:百度丫丫-情感女声
27 request.setAue(3); // 音频格式选择 3:mp3格式(默认) 4:pcm-16k 5:pcm-8k 6:wav格式
28 // 采样率,仅支持将采样率降采为16k。
29 // request.setSamplingRate();
30
31 // 要合成的文本片段数组
32 String[] texts = {
33 "飞船在深空中缓缓滑行,舷窗外的星云泛着微",
34 "弱的蓝光。指挥官林远重新校准了导航系统,",
35 "确保他们不会偏离既定航道。远处,一颗无名",
36 "行星的影子逐渐浮现,其表面布满裂痕,仿佛",
37 "经历过无数次天体撞击。科研员苏晴调出了能",
38 "量探测图,发现地壳深处竟有稳定的能量脉冲",
39 "反应。她压低声音对林远说:“长官,我们可",
40 "能发现了一种未知文明的遗迹。”众人心头猛",
41 "地一震,飞船上的气氛顿时紧张起来,所有仪",
42 "器的读数都在快速变化,像在预示着什么即将",
43 "发生。飞船继续逼近,那股神秘能量愈发清晰。"
44 };
45
46 // 一次性输入
47 // String[] texts = {"飞船在深空中缓缓滑行,舷窗外的星云泛着微弱的蓝光。指挥官林远重新校准了导航系统,确保他们不会偏离既定航道。远处,一颗无名行星的影子逐渐浮现,其表面布满裂痕,仿佛经历过无数次天体撞击。科研员苏晴调出了能量探测图,发现地壳深处竟有稳定的能量脉冲反应。她压低声音对林远说:“长官,我们可能发现了一种未知文明的遗迹。”众人心头猛地一震,飞船上的气氛顿时紧张起来,所有仪器的读数都在快速变化,像在预示着什么即将发生。飞船继续逼近,那股神秘能量愈发清晰。"};
48
49 // 文件合成路径
50 String outputPath = "output.mp3";
51
52 // 创建同步锁存器
53 CountDownLatch completionLatch = new CountDownLatch(1);
54
55 // 创建监听器
56 StreamTtsListener listener = new StreamTtsListener() {
57 private FileOutputStream fos;
58
59 @Override
60 public void onSynthesisStart(String sessionId) {
61 LOGGER.info("Stream synthesis started, sessionId: {}", sessionId);
62 try {
63 fos = new FileOutputStream(outputPath);
64 } catch (Exception e) {
65 e.printStackTrace();
66 }
67 }
68
69 @Override
70 public void onAudioData(String sessionId, byte[] data) {
71 LOGGER.info("Received audio data, length: {} byte, sessionId: {}", data.length, sessionId);
72 // 将音频数据写入文件
73 try {
74 if (fos != null) {
75 fos.write(data);
76 }
77 } catch (IOException e) {
78 e.printStackTrace();
79 }
80 }
81
82 @Override
83 public void onSynthesisEnd(String sessionId) {
84 LOGGER.info("Stream synthesis ended, sessionId: {}", sessionId);
85 try {
86 if (fos != null) {
87 fos.close();
88 }
89 } catch (IOException e) {
90 e.printStackTrace();
91 }
92 LOGGER.info("Audio file saved as {}", outputPath);
93 // 释放锁存器
94 completionLatch.countDown();
95 }
96
97 @Override
98 public void onSynthesisFail(JSONObject response) {
99 LOGGER.error("Stream synthesis failed: {}", response.toString());
100 try {
101 if (fos != null) {
102 fos.close();
103 }
104 } catch (Exception e) {
105 e.printStackTrace();
106 } finally {
107 // 出现错误也释放锁存器
108 completionLatch.countDown();
109 }
110 }
111 };
112
113 // 创建流式合成器
114 StreamTtsSession session = null;
115 try {
116
117 session = client.streamSynthesis(client, request, listener);
118
119 // 启动流式合成
120 session.start();
121
122 // 发送文本片段
123 for (String text : texts) {
124 LOGGER.info("Send Text Request: {}", text);
125 session.process(text);
126 // 模拟用户间隔输入文本的场景
127 Thread.sleep(500);
128 }
129
130 // 停止流式合成,默认时间为60s,可根据文本长度自定义时间
131 session.stop(); // 可传入参数 60000
132 LOGGER.info("Stream synthesis stopped!");
133
134 // 等待合成完成,最多等待120秒,可根据文本长度自定义时间
135 if (completionLatch.await(120, TimeUnit.SECONDS)) {
136 LOGGER.info("Synthesis completed!");
137 } else {
138 LOGGER.error("Synthesis timeout!");
139 }
140 } catch (Exception e) {
141 LOGGER.error("Error processing: {}", e.getMessage(), e);
142 e.printStackTrace();
143 } finally {
144 if (session != null) {
145 session.close(); //关闭连接
146 }
147 }
148 }
149}
在上面代码中,常量APP_ID在百度云控制台中创建,常量API_KEY与SECRET_KEY是在创建完毕应用后,系统分配给用户的,均为字符串,用于标识用户,为访问做签名验证,可在AI服务控制台中的应用列表中查看。
配置AipSpeech
如果用户需要配置AipSpeech的一些细节参数,可以在构造AipSpeech之后调用接口设置参数,目前只支持以下参数:
| 接口 | 说明 |
|---|---|
| setConnectionTimeoutInMillis | 建立连接的超时时间(单位:毫秒) |
| setSocketTimeoutInMillis | 通过打开的连接传输数据的超时时间(单位:毫秒) |
| setHttpProxy | 设置http代理服务器 |
| setSocketProxy | 设置socket代理服务器 (http和socket类型代理服务器只能二选一) |
接口说明
流式语音合成
详细文档参考官网:https://ai.baidu.com/ai-doc/SPEECH/lm5xd63rn
接口描述
基于该接口,开发者可以轻松获取流式语音合成能力。流式合成相比普通合成具有以下优势:
- 实时性更强:边合成边播放,减少等待时间
- 内存占用更小:无需等待全部合成完毕再获取音频
- 用户体验更好:可以更快听到第一段语音内容
功能说明
- 建议文本不超过2000 GBK字节,即1000个汉字或者字母数字
- 输入的文本必须采用UTF-8编码
- 支持多音字通过标注自行定义发音。格式如:重(chong2)报集团
请求说明
流式语音合成采用WebSocket协议进行通信,支持长文本分段传输合成。 Java Demo 如下:
其中,文本支持分段输入,也支持一次性输入,但需注意长度限制。
1import com.baidu.aip.speech.AipSpeech;
2import com.baidu.aip.speech.StreamTtsListener;
3import com.baidu.aip.speech.StreamTtsRequest;
4import com.baidu.aip.speech.StreamTtsSession;
5import org.json.JSONObject;
6
7import java.io.FileOutputStream;
8import java.io.IOException;
9import java.util.concurrent.CountDownLatch;
10import java.util.concurrent.TimeUnit;
11
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15/**
16 * 流式TTS合成示例
17 */
18public class StreamTtsExample {
19 // 设置APPID/AK/SK
20 public static final String APP_ID = "你的 App ID";
21 public static final String API_KEY = "你的 Api Key";
22 public static final String SECRET_KEY = "你的 Secret Key";
23 private static final Logger LOGGER = LoggerFactory.getLogger(StreamTtsExample.class);
24
25 public static void main(String[] args) {
26 // 初始化一个AipSpeech
27 AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
28
29 // 可选:设置网络连接参数
30 client.setConnectionTimeoutInMillis(2000);
31 client.setSocketTimeoutInMillis(60000);
32
33 // 调用流式合成接口
34 StreamTtsSynthesis(client);
35 }
36
37 private static void StreamTtsSynthesis(AipSpeech client) {
38 // 创建请求参数
39 StreamTtsRequest request = new StreamTtsRequest();
40 request.setSpd(5); // 语速,取值0-15,默认为5中语速
41 request.setPit(5); // 音调,取值0-15,默认为5中语调
42 request.setVol(5); // 音量,取值0-15,默认为5中音量
43 request.setPer(4146); // 发音人选择, 4146:百度丫丫-情感女声
44 request.setAue(3); // 音频格式选择 3:mp3格式(默认) 4:pcm-16k 5:pcm-8k 6:wav格式
45 // 采样率,仅支持将采样率降采为16k。
46 // request.setSamplingRate();
47
48 // 要合成的文本片段数组
49 String[] texts = {
50 "飞船在深空中缓缓滑行,舷窗外的星云泛着微",
51 "弱的蓝光。指挥官林远重新校准了导航系统,",
52 "确保他们不会偏离既定航道。远处,一颗无名",
53 "行星的影子逐渐浮现,其表面布满裂痕,仿佛",
54 "经历过无数次天体撞击。科研员苏晴调出了能",
55 "量探测图,发现地壳深处竟有稳定的能量脉冲",
56 "反应。她压低声音对林远说:“长官,我们可",
57 "能发现了一种未知文明的遗迹。”众人心头猛",
58 "地一震,飞船上的气氛顿时紧张起来,所有仪",
59 "器的读数都在快速变化,像在预示着什么即将",
60 "发生。飞船继续逼近,那股神秘能量愈发清晰。"
61 };
62
63 // 一次性输入
64 // String[] texts = {"飞船在深空中缓缓滑行,舷窗外的星云泛着微弱的蓝光。指挥官林远重新校准了导航系统,确保他们不会偏离既定航道。远处,一颗无名行星的影子逐渐浮现,其表面布满裂痕,仿佛经历过无数次天体撞击。科研员苏晴调出了能量探测图,发现地壳深处竟有稳定的能量脉冲反应。她压低声音对林远说:“长官,我们可能发现了一种未知文明的遗迹。”众人心头猛地一震,飞船上的气氛顿时紧张起来,所有仪器的读数都在快速变化,像在预示着什么即将发生。飞船继续逼近,那股神秘能量愈发清晰。"};
65
66 // 文件合成路径
67 String outputPath = "output.mp3";
68
69 // 创建同步锁存器
70 CountDownLatch completionLatch = new CountDownLatch(1);
71
72 // 创建监听器
73 StreamTtsListener listener = new StreamTtsListener() {
74 private FileOutputStream fos;
75
76 @Override
77 public void onSynthesisStart(String sessionId) {
78 LOGGER.info("Stream synthesis started, sessionId: {}", sessionId);
79 try {
80 fos = new FileOutputStream(outputPath);
81 } catch (Exception e) {
82 e.printStackTrace();
83 }
84 }
85
86 @Override
87 public void onAudioData(String sessionId, byte[] data) {
88 LOGGER.info("Received audio data, length: {} byte, sessionId: {}", data.length, sessionId);
89 // 将音频数据写入文件
90 try {
91 if (fos != null) {
92 fos.write(data);
93 }
94 } catch (IOException e) {
95 e.printStackTrace();
96 }
97 }
98
99 @Override
100 public void onSynthesisEnd(String sessionId) {
101 LOGGER.info("Stream synthesis ended, sessionId: {}", sessionId);
102 try {
103 if (fos != null) {
104 fos.close();
105 }
106 } catch (IOException e) {
107 e.printStackTrace();
108 }
109 LOGGER.info("Audio file saved as {}", outputPath);
110 // 释放锁存器
111 completionLatch.countDown();
112 }
113
114 @Override
115 public void onSynthesisFail(JSONObject response) {
116 LOGGER.error("Stream synthesis failed: {}", response.toString());
117 try {
118 if (fos != null) {
119 fos.close();
120 }
121 } catch (Exception e) {
122 e.printStackTrace();
123 } finally {
124 // 出现错误也释放锁存器
125 completionLatch.countDown();
126 }
127 }
128 };
129
130 // 创建流式合成器
131 StreamTtsSession session = null;
132 try {
133
134 session = client.streamSynthesis(client, request, listener);
135
136 // 启动流式合成
137 session.start();
138
139 // 发送文本片段
140 for (String text : texts) {
141 LOGGER.info("Send Text Request: {}", text);
142 session.process(text);
143 // 模拟用户间隔输入文本的场景
144 Thread.sleep(500);
145 }
146
147 // 停止流式合成,默认时间为60s,可根据文本长度自定义时间
148 session.stop(); // 可传入参数 60000
149 LOGGER.info("Stream synthesis stopped!");
150
151 // 等待合成完成,最多等待120秒,可根据文本长度自定义时间
152 if (completionLatch.await(120, TimeUnit.SECONDS)) {
153 LOGGER.info("Synthesis completed!");
154 } else {
155 LOGGER.error("Synthesis timeout!");
156 }
157 } catch (Exception e) {
158 LOGGER.error("Error processing: {}", e.getMessage(), e);
159 e.printStackTrace();
160 } finally {
161 if (session != null) {
162 session.close(); //关闭连接
163 }
164 }
165 }
166}
StreamTtsRequest参数详解
| 参数名称 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| spd | int | 可选 | 语速,取值 0-15,默认为 5 |
| pit | int | 可选 | 音调,取值 0-15,默认为 5 |
| vol | int | 可选 | 音量,基础音库取值0-9,其他音库取值 0-15,默认为 5 |
| per | int | 必填 | 发音人选择,具体值参考官方文档 |
| aue | int | 可选 | 音频格式,3=mp3-16k/24k,4=pcm-16k/24k,5=pcm-8k,6=wav-16k/24k,默认为3 |
| audio_ctrl | string | 可选 | 采样率,仅支持将采样率降采为16k。(格式:{"sampling_rate":16000}) |
StreamTtsListener回调方法
| 方法 | 说明 |
|---|---|
| onSynthesisStart | 当WebSocket连接打开,服务端返回开始合成响应时调用 |
| onAudioData | 当收到音频数据时调用 |
| onSynthesisEnd | 当合成结束时调用 |
| onSynthesisFail | 当发生错误时调用 |
返回说明
流式语音合成通过监听器回调方式返回结果:
- onSynthesisStart: 合成开始通知
- onAudioData: 音频数据,可直接用于播放或保存
- onSynthesisEnd: 合成结束通知
- onSynthesisFail: 错误信息,包含错误码和错误描述
错误处理
流式TTS合成过程中可能出现多种类型的错误:
- 连接错误:WebSocket连接失败
- 认证错误:access_token无效或过期
- 参数错误:请求参数不符合规范
- 服务端错误:服务器内部错误
- 网络超时:请求超时
建议在onSynthesisFail回调中进行相应处理。
注意事项
- 会话管理:每个StreamTtsSynthesizer实例代表一个独立的合成会话,请勿并发使用同一实例
- 资源释放:使用完毕后务必调用synthesizer.close()方法释放连接资源
- 超时设置:合理设置start()和stop()方法的超时时间
- 文本分割:长文本建议按语义分割成适当长度的片段分别发送
- 异常处理:注意捕获并处理可能抛出的各种异常,包括网络异常、参数异常等
- 音频格式:根据实际需求选择合适的音频格式,不同格式的数据大小和质量有所差异
