赞
踩
不废话,直接上code
- package com.iflytek.voicecloud.webapi.demo;
-
- import com.google.gson.Gson;
- import com.google.gson.JsonObject;
- import okhttp3.*;
- import okio.ByteString;
-
- import javax.crypto.Mac;
- import javax.crypto.spec.SecretKeySpec;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.net.URL;
- import java.nio.charset.Charset;
- import java.text.SimpleDateFormat;
- import java.util.Base64;
- import java.util.Date;
- import java.util.Locale;
- import java.util.TimeZone;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
-
-
- public class WebTTSWS {
- private static final String hostUrl = "https://tts-api.xfyun.cn/v2/tts"; //http url 不支持解析 ws/wss schema
- private static final String appid = "";//到控制台-语音合成页面获取
- private static final String apiSecret = "";//到控制台-语音合成页面获取
- private static final String apiKey = "";//到控制台-语音合成页面获取
- private static final String text = "在全系5款车型中,上市专享版的性价比最为突出,在有限的价格下提供了大多数实用配置,而且是唯一标配车内氛围灯的车型,不失为价值之选。时尚致雅型和时尚动感型居于中配角色,配置方面较低配车型更加全面,面子和里子都比较到位,符合人们对豪华品牌的期待,同样值得考虑。";
- public static final Gson json = new Gson();
-
-
-
- public static class WaveHeader {
-
- public final char fileID[] = { 'R', 'I', 'F', 'F' };
- public int fileLength;
- public char wavTag[] = { 'W', 'A', 'V', 'E' };;
- public char FmtHdrID[] = { 'f', 'm', 't', ' ' };
- public int FmtHdrLeth;
- public short FormatTag;
- public short Channels;
- public int SamplesPerSec;
- public int AvgBytesPerSec;
- public short BlockAlign;
- public short BitsPerSample;
- public char DataHdrID[] = { 'd', 'a', 't', 'a' };
- public int DataHdrLeth;
-
- public byte[] getHeader() throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- writeChar(bos, fileID);
- writeInt(bos, fileLength);
- writeChar(bos, wavTag);
- writeChar(bos, FmtHdrID);
- writeInt(bos, FmtHdrLeth);
- writeShort(bos, FormatTag);
- writeShort(bos, Channels);
- writeInt(bos, SamplesPerSec);
- writeInt(bos, AvgBytesPerSec);
- writeShort(bos, BlockAlign);
- writeShort(bos, BitsPerSample);
- writeChar(bos, DataHdrID);
- writeInt(bos, DataHdrLeth);
- bos.flush();
- byte[] r = bos.toByteArray();
- bos.close();
- return r;
- }
-
- private void writeShort(ByteArrayOutputStream bos, int s) throws IOException {
- byte[] mybyte = new byte[2];
- mybyte[1] = (byte) ((s << 16) >> 24);
- mybyte[0] = (byte) ((s << 24) >> 24);
- bos.write(mybyte);
- }
-
- private void writeInt(ByteArrayOutputStream bos, int n) throws IOException {
- byte[] buf = new byte[4];
- buf[3] = (byte) (n >> 24);
- buf[2] = (byte) ((n << 8) >> 24);
- buf[1] = (byte) ((n << 16) >> 24);
- buf[0] = (byte) ((n << 24) >> 24);
- bos.write(buf);
- }
-
- private void writeChar(ByteArrayOutputStream bos, char[] id) {
- for (int i = 0; i < id.length; i++) {
- char c = id[i];
- bos.write(c);
- }
- }
- }
-
-
-
-
- public static void convertAudioFiles(String src, String target) throws Exception {
- FileInputStream fis = new FileInputStream(src);
- FileOutputStream fos = new FileOutputStream(target);
-
- //计算长度
- byte[] buf = new byte[1024 * 4];
- int size = fis.read(buf);
- int PCMSize = 0;
- while (size != -1) {
- PCMSize += size;
- size = fis.read(buf);
- }
- fis.close();
-
- //填入参数,比特率等等。这里用的是16位单声道 8000 hz
- WaveHeader header = new WaveHeader();
- //长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
- header.fileLength = PCMSize + (44 - 8);
- header.FmtHdrLeth = 16;
- header.BitsPerSample = 16;
- header.Channels = 1;
- header.FormatTag = 0x0001;
- header.SamplesPerSec = 14500;
- header.BlockAlign = (short)(header.Channels * header.BitsPerSample / 8);
- header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
- header.DataHdrLeth = PCMSize;
-
- byte[] h = header.getHeader();
-
- assert h.length == 44; //WAV标准,头部应该是44字节
- //write header
- fos.write(h, 0, h.length);
- //write data stream
- fis = new FileInputStream(src);
- size = fis.read(buf);
- while (size != -1) {
- fos.write(buf, 0, size);
- size = fis.read(buf);
- }
- fis.close();
- fos.close();
- System.out.println("Convert OK!");
- }
-
-
-
-
-
-
-
- public static void main(String[] args) throws Exception {
- // 构建鉴权url
- String authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);
- OkHttpClient client = new OkHttpClient.Builder().build();
- //将url中的 schema http://和https://分别替换为ws:// 和 wss://
- String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
- Request request = new Request.Builder().url(url).build();
- // 存放音频的文件
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
- String date = sdf.format(new Date());
- File f = new File("resource/tts/" + date + ".pcm");
- if (!f.exists()) {
- f.createNewFile();
- }
- FileOutputStream os = new FileOutputStream(f);
- WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
- @Override
- public void onOpen(WebSocket webSocket, Response response) {
- super.onOpen(webSocket, response);
- try {
- System.out.println(response.body().string());
- } catch (IOException e) {
- e.printStackTrace();
- }
- //发送数据
- JsonObject frame = new JsonObject();
- JsonObject business = new JsonObject();
- JsonObject common = new JsonObject();
- JsonObject data = new JsonObject();
- // 填充common
- common.addProperty("app_id", appid);
- //填充business
- business.addProperty("aue", "raw");
- business.addProperty("tte", "UTF8");
- business.addProperty("ent", "intp65");
- business.addProperty("vcn", "x_yifeng");//到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200
- business.addProperty("pitch", 50);
- business.addProperty("speed", 60);
- //填充data
- data.addProperty("status", 2);//固定位2
- data.addProperty("text", Base64.getEncoder().encodeToString(text.getBytes()));
- data.addProperty("encoding", "");
- //填充frame
- frame.add("common", common);
- frame.add("business", business);
- frame.add("data", data);
- webSocket.send(frame.toString());
- }
- @Override
- public void onMessage(WebSocket webSocket, String text) {
- super.onMessage(webSocket, text);
- //处理返回数据
- System.out.println("receive=>" + text);
- ResponseData resp = null;
- try {
- resp = json.fromJson(text, ResponseData.class);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (resp != null) {
- if (resp.getCode() != 0) {
- System.out.println("error=>" + resp.getMessage() + " sid=" + resp.getSid());
- return;
- }
- if (resp.getData() != null) {
- String result = resp.getData().audio;
- byte[] audio = Base64.getDecoder().decode(result);
- try {
- os.write(audio);
- os.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (resp.getData().status == 2) {
- // todo resp.data.status ==2 说明数据全部返回完毕,可以关闭连接,释放资源
- System.out.println("session end ");
- System.out.println("合成的音频文件保存在:" + f.getPath());
- webSocket.close(1000, "");
-
- try {
- convertAudioFiles(f.getPath(),f.getPath()+".mp3");
- } catch (Exception e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
-
-
- try {
-
-
- os.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- @Override
- public void onMessage(WebSocket webSocket, ByteString bytes) {
- super.onMessage(webSocket, bytes);
- }
- @Override
- public void onClosing(WebSocket webSocket, int code, String reason) {
- super.onClosing(webSocket, code, reason);
- System.out.println("socket closing");
- }
- @Override
- public void onClosed(WebSocket webSocket, int code, String reason) {
- super.onClosed(webSocket, code, reason);
- System.out.println("socket closed");
- }
- @Override
- public void onFailure(WebSocket webSocket, Throwable t, Response response) {
- super.onFailure(webSocket, t, response);
- System.out.println("connection failed");
- }
- });
- }
- public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
- URL url = new URL(hostUrl);
- SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
- format.setTimeZone(TimeZone.getTimeZone("GMT"));
- String date = format.format(new Date());
- StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
- append("date: ").append(date).append("\n").//
- append("GET ").append(url.getPath()).append(" HTTP/1.1");
- Charset charset = Charset.forName("UTF-8");
- Mac mac = Mac.getInstance("hmacsha256");
- SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
- mac.init(spec);
- byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
- String sha = Base64.getEncoder().encodeToString(hexDigits);
- String authorization = String.format("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
- HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
- addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset))).//
- addQueryParameter("date", date).//
- addQueryParameter("host", url.getHost()).//
- build();
- return httpUrl.toString();
- }
- public static class ResponseData {
- private int code;
- private String message;
- private String sid;
- private Data data;
- public int getCode() {
- return code;
- }
- public String getMessage() {
- return this.message;
- }
- public String getSid() {
- return sid;
- }
- public Data getData() {
- return data;
- }
- }
- public static class Data {
- private int status; //标志音频是否返回结束 status=1,表示后续还有音频返回,status=2表示所有的音频已经返回
- private String audio; //返回的音频,base64 编码
- private String ced; // 合成进度
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。