科大讯飞TTS接口调用保存为mp3格式

news/2024/11/29 2:34:54/

不废话,直接上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 schemaprivate 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 hzWaveHeader 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 headerfos.write(h, 0, h.length);//write data streamfis = 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 {// 构建鉴权urlString 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() {@Overridepublic 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();// 填充commoncommon.addProperty("app_id", appid);//填充businessbusiness.addProperty("aue", "raw");business.addProperty("tte", "UTF8");business.addProperty("ent", "intp65");business.addProperty("vcn", "x_yifeng");//到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200business.addProperty("pitch", 50);business.addProperty("speed", 60);//填充datadata.addProperty("status", 2);//固定位2data.addProperty("text", Base64.getEncoder().encodeToString(text.getBytes()));data.addProperty("encoding", "");//填充frameframe.add("common", common);frame.add("business", business);frame.add("data", data);webSocket.send(frame.toString());}@Overridepublic 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 blocke1.printStackTrace();}try {os.close();} catch (IOException e) {e.printStackTrace();}}}}}@Overridepublic void onMessage(WebSocket webSocket, ByteString bytes) {super.onMessage(webSocket, bytes);}@Overridepublic void onClosing(WebSocket webSocket, int code, String reason) {super.onClosing(webSocket, code, reason);System.out.println("socket closing");}@Overridepublic void onClosed(WebSocket webSocket, int code, String reason) {super.onClosed(webSocket, code, reason);System.out.println("socket closed");}@Overridepublic 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;  // 合成进度}
}

 


http://www.ppmy.cn/news/245339.html

相关文章

基于嵌入式Linux的MP3播放器的设计与实现

摘要&#xff1a;本文详细介绍了嵌入式系统的特点以及嵌入式系统开发的流程&#xff0c;分析基于嵌入式Linux的MP3播放器的关键技术&#xff0c;设计和实现了一种基于嵌入式系统的 MP3 播放器。该播放器利用 QT 技术和开源的音频解码器 libmad编程实现&#xff0c;运行在嵌入式…

我想做个MP3,要怎么入手?

从我更新的频率&#xff0c;大家应该猜出来了&#xff0c;最近有点忙。忙完了设备调试的工作&#xff0c;又来了个画图的活。本来改动不大&#xff0c;但怎料...哎&#xff0c;一言难尽。 今天回答一个粉丝的提问&#xff1a; 看完这个回复&#xff0c;我依然没明白他到底想做哪…

MP3结构与组成

1、MP3是什么&#xff1f; MP3是一种有损数字音频压缩格式。全称是Mpeg-1 audio Layer 3&#xff0c;其中MPEG是Moving Picture Experts Group的缩写&#xff0c;意思是动态图象专家组。所谓“有损压缩音频格式”也就是对数字音频使用了对音质有损耗的压缩方式&#xff0c;以达…

苹果mp3软件_软件 | 剪辑软件大合集2020405

软件下载必看&#xff1a;☛☛查看软件下载以及安装问题 目录导航 ① 手机剪辑软件④ 平面设计② Adobe系列⑤ 3D建模③ 视频制作⑥ 其他类 手机剪辑APP 手机剪辑软件&#xff0c;为什么要先介绍这个了。除了方便之外还是方便。它能快速帮你剪辑制作视频发到朋友圈&#xff…

基于alsa和libmad嵌入式mp3播放器

可移植ok6410 的mp3播放器&#xff0c;基于alsa和libmad库&#xff0c;内含编译好的库和播放器以及源代码&#xff0c;解压后可直接运行&#xff0c;和以移植好的mplayer官方播放器&#xff08;可快进 暂停 时间轴 音量控制等&#xff09; 源码及移植库文件下载地址&#xff1…

MP3基本知识及构成

1、MP3是什么&#xff1f; MP3是一种有损数字音频压缩格式。全称是Mpeg-1 audio Layer 3&#xff0c;其中MPEG是Moving Picture Experts Group的缩写&#xff0c;意思是动态图象专家组。所谓“有损压缩音频格式”也就是对数字音频使用了对音质有损耗的压缩方式&#xff0c;以达…

【毕业设计】基于单片机的MP3设计与实现 - stm32

文章目录 1 简介2 主要器件3 实现效果4 设计原理核心算法&#xff1a;音频解码流程 5 部分实现代码6 最后 1 简介 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天向大家介绍一个学长做的单片机项目 基于单片机的MP3设计与实现 大家可用于 课程设计 或 毕业…

小白必看:零基础入门网络安全

1、什么是网络安全&#xff1f; 官方的回答&#xff1a;指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而遭受到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。 具有保密性、完整性、可用性、可控性…