logo
电话400 898 2016
预约试用
开放平台
En
尊敬的开发者,您好! 标贝科技的开发文档已更换新的地址,旧版文档地址将会在2023年12月31日下线, 给您带来不便,敬请谅解! 立即查看
产品简介 产品简介
基本概念 基本概念
平台新手指引 平台新手指引
计价模式 计价模式
开发者文档下拉
开放平台计价
定制服务计价
获取访问令牌 获取访问令牌
语音合成 语音合成
开发者文档下拉
接口说明
发音人列表
短文本合成 开发者文档下拉
Android SDK
iOS SDK
C++(Linux) SDK
RESTful API
Websocket API
长文本合成 开发者文档下拉
长文本合成RESTful API
长文本合成Websocket API
离线合成 开发者文档下拉
模型文件说明
离线合成(普通版) Android SDK
离线合成(普通版) iOS SDK
离线合成(精品版) Android SDK
离线合成(精品版) iOS SDK
XML标签
SSML标签
语音合成时间戳功能
语音识别 语音识别
开发者文档下拉
音频格式说明
一句话识别 开发者文档下拉
RESTful API
Websocket API
Android SDK
iOS SDK
实时长语音识别 开发者文档下拉
Websocket API
Android SDK
iOS SDK
录音文件识别 开发者文档下拉
RESTful API
自学习工具 开发者文档下拉
热词
个性化模型
声音复刻 声音复刻
开发者文档下拉
定制模型 开发者文档下拉
RESTful API
Android SDK
iOS SDK
定制声音合成 开发者文档下拉
短文本合成RESTful API
长文本合成Websocket API
声音转换 声音转换
开发者文档下拉
发音人列表
Websocket API
Android SDK
iOS SDK
离线声音转换 离线声音转换
开发者文档下拉
发音人列表
Android SDK
iOS SDK
声纹识别 声纹识别
开发者文档下拉
RESTful API
声音理解 声音理解
开发者文档下拉
RESTful API
协议规则 协议规则
开发者文档下拉
平台服务协议
平台通用规则
法律声明及隐私政策
服务等级协议SLA
常见问题 常见问题
开发者文档下拉
语音合成
语音识别

短文本合成Websocket API

功能介绍

语音合成Websocket API满足用户希望尽快获得合成音频的场景,输入文本后音频以流的形式持续返回直至最后一帧成功返回。

参数设置

  • 支持设置合成音频的格式: PCM
  • 支持设置合成音频的采样率: 8000Hz,16000Hz,24000Hz
  • 支持设置多种发音人
  • 支持设置音量、语速、语调
  • 支持返回时间戳信息
  • 支持设置多种语言:中文(zh),英文(eng),粤语(cat),四川话(sch),天津话(tjh),台湾话(tai),韩语(kr),巴葡语(bra),日语(jp),西班牙西语(ESP),墨西哥西语(MEX),维吾尔语(UYG)

websocket协议简介

  • WebSocket ( https://tools.ietf.org/html/rfc6455)是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
  • WebSocket和HTTP一样都是基于TCP的应用层协议。客户端开始建立WebSocket连接时要发送一个header标记了 Upgrade的HTTP请求,表示请求协议升级。所以服务器端做出响应是直接在现有的HTTP服务器软件和现有的端口上实现WebSocket协议,然后再回一个状态码为101的HTTP响应完成握手。握手完成后收发数据跟HTTP就没有关系了。
  • 握手部分的设计目的就是兼容现有的基于HTTP的服务端组件(web服务器软件)或者中间件(代理服务器软件)。这样一个端口就可以同时接受普通的HTTP请求或则WebSocket请求了。为了这个目的,WebSocket客户端的握手是一个 HTTP升级版的请求(HTTP Upgrade request)
  • 客户端发送一个请求
  • GET /tts/wsapi HTTP/1.1
    Host: openapi.data-baker.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    Origin: http://example.com
  • 服务端响应
  • HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
    Sec-WebSocket-Protocol: chat

使用方法

1. 创建账号和应用,详见平台新手指引,通过标贝开放平台/应用/服务获取client_id,client_secret

2. 发送请求获取access_token,详见获取访问令牌

3. 建立websocket连接

4. 实时发送需要合成的文字,具体参数详见 请求参数

5. 接收返回结果,具体参数定义详见响应结果说明。

6. 关闭连接。

服务地址

访问类型 说明 URL Host
外网访问 支持全部音色及语言 wss://openapi.data-baker.com/tts/wsapi openapi.data-baker.com

交互流程

请求参数

参数名称 类型 是否必填项 说明
access_token string yes 通过client_id,client_secret调用授权服务获得见 获取访问令牌
version string yes 版本信息,目前为1.0
tts_params jsonObject,且内部的字段均为string数据类型,其中text字段是必需字段且需进行base64编码 yes tts相关参数

tts相关参数如下:

参数名称 类型 是否必填项 说明
text string 合成的文本,使用UTF-8编码,一次请求最多不超过300个汉字,且需进行base64编码。
domain string 应用所属领域如导航、客服等,以数字进行编码,目前值固定为1
language string 合成请求文本的语言
ZH(中文和中英混)
ENG(纯英文,中文部分不会合成)
CAT(粤语)
SCH(四川话)
TJH(天津话)
TAI(台湾话)
KR(韩语)
BRA(巴葡语)
JP(日语)
ESP(西班牙西语)
MEX(墨西哥西语)
UYG(维吾尔语)
speed string 设置播放的语速,在0~9之间(支持浮点值),默认值为5
volume string 设置语音的音量,在0~9之间(只支持整型值),默认值为5
pitch string 设置语音的音调,在0~9之间,(支持浮点值),默认值为5
audiotype string 音频种类:
audiotype = 4,返回16K采样率的pcm格式,默认值
audiotype = 5,返回8K采样率的pcm格式
audiotype=5&rate=3,返回24K采样率的pcm格式
rate string rate=3,请求24k采样率时使用
voice_name string 发音人选择,如“Jiaojiao", 详见 发音人列表
spectrum string 高频频谱:取值范围1~20; 默认值为1,不调整频谱;
1代表不调整频谱;
1以上的值代表高频能量增加幅度, 值越大声音的高频部分增强越多,听起来更亮和尖细
spectrum_8k string 低频部分频谱:取值范围0~20;默认值为0,仅针对8K音频频谱的调整。 组合形式只有以下几种:
audiotype=5&spectrum_8k=xx
interval string 音子级别时间戳功能:
'0':关闭音子级别时间戳功能
'1':开启音子级别时间戳功能
enable_subtitles string 字级别时间戳功能,同interval=”1”一起使用:
'0':关闭字级别时间戳功能
'1':开启字级别时间戳功能
详细使用方法参考语音合成时间戳
silence string 设置标点符号静音时长:
'0':默认值
'1':句中标点停顿较短,适合直播、配音解说等场景
'2':句中标点停顿较长,适合朗诵、教学等场景
emo_type string 是(请求情感音色时) 在请求情感音色时,该参数是必填项。请求情感音色不存在的情感会报错。可选值参考 发音人列表-多情感/风格音色,如:sad
emo_intensity string 设置情感强度,在1~5之间(只支持整型值),不传时默认为3。

请求示例

{
    "access_token":" your_access_token",
    "version":"1.0",
    "tts_params":{
       "domain":"1",
       "interval":"1",
       "language":"zh",
       "voice_name":"Jiaojiao",
       "text":"5qCH6LSd56eR5oqA77yM5LiT5rOo5LqO5pm66IO96K+t6Z+z5oqA5pyv"//"标贝科技,专注于智能语音技术"
    }
}

Python示例代码

代码地址:Github

Python3示例:

import argparse
import json
import base64
from threading import Thread
import requests
import websocket
import wave


#websocket客户端
class Client:
    def __init__(self, data, uri):
        self.data = data
        self.uri = uri
        self.audio_data = b""

    #建立连接
    def connect(self):
        ws_app = websocket.WebSocketApp(uri,
                                        on_open=self.on_open,
                                        on_message=self.on_message,
                                        on_error=self.on_error,
                                        on_close=self.on_close)
        ws_app.run_forever()

    # 建立连接后发送消息
    def on_open(self, ws):
        print("sending..")
        def run(*args):
            ws.send(self.data)

        Thread(target=run).start()

    # 接收消息
    def on_message(self, ws, message):
        code = json.loads(message).get("code")
        if code != 90000:
            # 打印接口错误
            print(message)
        else:
            self.audio_data += base64.b64decode(bytes(json.loads(message).get("data")["audio_data"], encoding='utf-8'))
            if json.loads(message).get("data")["end_flag"] == 1:
                with wave.open('test.wav', 'wb') as wavfile:
                    wavfile.setparams((1, 2, 16000, 0, 'NONE', 'NONE'))
                    wavfile.writeframes(self.audio_data)
                ws.close()
                print("task finished successfully")

    # 打印错误
    def on_error(self, ws, error):
        print("error: ", str(error))

    # 关闭连接
    def on_close(ws):
        print("client closed.")


# 准备数据
def prepare_data(args, access_token):

    # 填写Header信息
    audiotype= args.audiotype
    voice_name = args.voice_name

    text = args.text
    # 单次调用不超过300个汉字
    if len(text) > 300:
        raise Exception("Text is too long. The maximum length of chinese character is 300")
    text_bytes = text.encode(encoding='UTF-8')
    text = str(base64.b64encode(text_bytes), encoding='UTF-8')
    tts_params = {"language": "ZH", "voice_name": voice_name, "audiotype": audiotype, "domain": "1", "text": text}

    data = {"access_token": access_token, "version": "1.0", "tts_params": tts_params}
    data = json.dumps(data)

    return data


# 获取命令行输入参数
def get_args():
    text = "今天天气不错哦!"
    parser = argparse.ArgumentParser(description='tts')
    parser.add_argument('-client_secret', type=str, required=True)
    parser.add_argument('-client_id', type=str, required=True)
    parser.add_argument('-file_save_path', type=str, required=True)
    parser.add_argument('--text', type=str, default=text)
    parser.add_argument('--audiotype', type=str, default='4')
    parser.add_argument('--voice_name', type=str, default='Lingling')
    args = parser.parse_args()

    return args


# 获取access_token用于鉴权
def get_access_token(client_secret, client_id):
    grant_type = "client_credentials"
    url = "https://openapi.data-baker.com/oauth/2.0/token?grant_type={}&client_secret={}&client_id={}" \
        .format(grant_type, client_secret, client_id)

    try:
        response = requests.post(url)
        response.raise_for_status()
    except Exception as e:
        print(response.text)
        raise Exception
    else:
        access_token = json.loads(response.text).get('access_token')
        return access_token


if __name__ == '__main__':
    try:
        args = get_args()

        # 获取access_token
        client_secret = args.client_secret
        client_id = args.client_id
        access_token = get_access_token(client_secret, client_id)

        # 准备数据
        data = prepare_data(args, access_token)

        uri = "wss://openapi.data-baker.com/tts/wsapi"
        # 建立Websocket连接
        client = Client(data, uri)
        client.connect()

        print('end')
    except Exception as e:
        print(e)
      

命令行执行

python online_tts.py -client_secret=您的client_secret -client_id=您的client_id -file_save_path=test.wav --text=欢迎使用标贝开放平台

JAVA示例代码

package com.databaker.web.tts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

/**
 * 短文本合成WebSocket API接口调用示例
 * 附:短文本合成Websocket API文档 【https://www.data-baker.com/specs/file/tts_api_websocket】
 * 注意:
 * 1.本demo展示了如何保存音频流到本地文件
 * 2.本demo仅完成基本的接口调用,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成
 *
 * @author data-baker
 */
public class TtsWebSocketDemo extends WebSocketListener {
    /**
     * 授权:需要在开放平台获取【https://ai.data-baker.com/】
     */
    private static final String clientId = "YOUR_CLIENT_ID";
    private static final String clientSecret = "YOUR_CLIENT_SECRET";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";

    private static final String hostUrl = "wss://openapi.data-baker.com/tts/wsapi";

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");

    /**
     * 开始时间
     */
    private static ThreadLocal<Date> timeBegin = ThreadLocal.withInitial(() -> new Date());

    /**
     * 结束时间
     */
    private static ThreadLocal<Date> timeEnd = ThreadLocal.withInitial(() -> new Date());

    private Date startTime;

    private String accessToken = getAccessToken();

    /**
     * utf-8编码,不超过300个汉字(即900字节)
     */
    private static Integer MAX_BYTE_LENGTH = 900;

    /**
     * 文本
     */
    private String text = "感谢使用标贝科技语音合成服务,祝您使用愉快!";
    /**
     * 发音人
     */
    private String voiceName = "Tiantian";

    /**
     * 保存结果文件的路径,开发者需要根据实际路径调整
     */
    private File resultFile;

    public TtsWebSocketDemo(File resultFile) {
        this.resultFile = resultFile;
    }

    public TtsWebSocketDemo(String text, File resultFile) {
        this.text = text;
        this.resultFile = resultFile;
    }

    public TtsWebSocketDemo(String text, String voiceName, File resultFile) {
        this.text = text;
        this.voiceName = voiceName;
        this.resultFile = resultFile;
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        this.startTime = timeBegin.get();
        new Thread(() -> {
            //连接成功,开始发送数据
            //发送文本
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("access_token", accessToken);
            jsonObject.put("version", "1.0");
            //填充asr_params
            JSONObject ttsParams = new JSONObject();
            //domain非必填
            ttsParams.put("domain", "1");
            ttsParams.put("interval", "0");
            ttsParams.put("language", "ZH");
            ttsParams.put("voice_name", voiceName);

            ttsParams.put("text", Base64.getEncoder().encodeToString(text.getBytes(Charset.forName("UTF-8"))));
            jsonObject.put("tts_params", ttsParams);
            System.out.println("dataSent:" + text);
            webSocket.send(jsonObject.toString());

            System.out.println("all data is send");
        }).start();
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        JSONObject resp = JSON.parseObject(text);
        if (resp != null) {
            if (resp.getInteger("code") != 90000) {
                System.out.println("code=>" + resp.getInteger("code") + " error=>" + resp.getString("message") + " trace_id=" + resp.getString("trace_id"));
                //关闭连接
                webSocket.close(1000, "");
                System.out.println("发生错误,关闭连接");
                return;
            }
            JSONObject dataObject = resp.getJSONObject("data");
            if (dataObject != null) {
                if (StringUtils.isNotEmpty(dataObject.getString("audio_data"))) {
                    //写入文件
                    FileOutputStream out = null;
                    try {
                        out = new FileOutputStream(resultFile, true);
                        byte[] b = Base64.getDecoder().decode(dataObject.getString("audio_data"));
                        out.write(b);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (out != null) {
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                if (dataObject.getInteger("end_flag") == 1) {
                    //说明数据全部返回完毕,可以关闭连接,释放资源
                    System.out.println("session end,tts finished. ");
                    System.out.println(sdf.format(startTime) + "开始");
                    System.out.println(sdf.format(timeEnd.get()) + "结束");
                    System.out.println("耗时:" + (timeEnd.get().getTime() - startTime.getTime()) + "ms");
                    webSocket.close(1000, "");
                }
            }
        }
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        try {
            if (null != response) {
                int code = response.code();
                System.out.println("onFailure code:" + code);
                System.out.println("onFailure body:" + response.body().string());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 测试方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().url(hostUrl).build();
        File file = new File("src/main/resources/tts1.pcm");
        //测试文本
        String ttsTestText = "教育部13日召开新闻通气会表示,暑期托管服务主要面向确有需求的家庭和学生,并由家长学生自愿选择参加。托管服务应以看护为主,合理组织提供一些集体游戏活动、文体活动、阅读指导、综合实践、兴趣拓展、作业辅导等服务,但不得组织集体补课、讲授新课。关于暑期托管变成第三学期的说法是不符合实际的。";
        //测试简单调用
        if ((ttsTestText.getBytes(Charset.forName("UTF-8"))).length > MAX_BYTE_LENGTH) {
            //单次调用长度不能超过300汉字即900字节
            //本demo策略是长度过长则直接返回,实际使用过程中可以进行文本切割
            System.out.println("文本不能超过300个汉字");
            return;
        }
        client.newWebSocket(request, new TtsWebSocketDemo(ttsTestText, file));
    }

    public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                //解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }
}
      

PHP示例代码

<?php
    ini_set("max_execution_time", "300");
    require_once "websocket-php/vendor/autoload.php";
    //1.获取token链接
    $client_secret = '***'; //应用secret
    $client_id = '***'; //应用id
    $grant_type = 'client_credentials'; //固定格式
    $url = 'https://openapi.data-baker.com/oauth/2.0/token?grant_type='.$grant_type.'&client_id='.$client_id.'&client_secret='.$client_secret;

    //curl get请求
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //信任任何证书
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // 检查证书中是否设置域名,0不验证
    $token_res = curl_exec($ch);

    //如果错误 查看错误信息
    if(curl_errno($ch))
    {
        print curl_error($ch);
    }
    curl_close($ch);

    //进行token信息解析
    $token_info = json_decode($token_res,1);
    $access_token = $token_info['access_token'];    //获取到的token信息
    //var_dump($access_token);die;
    //$access_token = '***';

    //2.短文本合成
    $url = 'wss://openapi.data-baker.com/tts/wsapi';
    $file_path = './test.txt';//文件路径 必须utf-8编码

    //定义请求方法
    $data_param['access_token'] = $access_token;
    $data_param['version'] = '1.0';
    $data_param['tts_params']['domain'] = '1';
    $data_param['tts_params']['language'] = 'ZH';
    $data_param['tts_params']['voice_name'] = 'Jiaojiao';

    //发送数据请求 每次发送不超过300个汉字
    $client = new \WebSocket\Client($url); //实例化
    $handle = fopen($file_path,'rb');
    $audio_info = fread($handle,900); //三个字节即一个汉字字符(UTF-8)
    $data_param['tts_params']['text'] = base64_encode($audio_info);
    $data = json_encode($data_param);
    $client->send($data); //发送数据

    //监听数据
    $info_list = [];
    $flag = true;
    while ($flag) {
        try {
            $message = $client->receive();//获取数据
            $result_info = json_decode($message,1);
            if($result_info['code'] == 90000){
                $info_list[$result_info['data']['idx']] = $result_info['data'];
            }else{
                throw new Exception($result_info['message']);
            }
            if($result_info['data']['end_flag']==1) $flag=false;//最后一包数据获取完成 停止获取数据
            //var_dump($result_info);
        } catch (\WebSocket\ConnectionException $e) {
            die($e->getMessage());
        }
    }
    //对获取数据进行处理 (说明,根据业务逻辑情况使用,本示例对返回信息一次性写入)
    if($info_list){
        ksort($info_list);//进行升序排序(说明,酌情使用,本示例对返回识别段落进行了二次排序)
        $file_name = './test.pcm';
        $handle=fopen($file_name,"w");
        foreach ($info_list as $v){
            //写入文件
            fwrite($handle, base64_decode($v['audio_data']));
        }
        die("识别音频保存完成");
    }else{
        die("获取的数据为空");
    }
      

GO示例代码

package main

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/gorilla/websocket"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

type AuthInfo struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
	Scope       string `json:"scope"`
}

type ReqTtsParams struct {
	Domain    string `json:"domain"`
	Interval  string `json:"interval,omitempty"`
	Language  string `json:"language"`
	VoiceName string `json:"voice_name"`
	Text      string `json:"text"`
	Audiotype string `json:"audiotype,omitempty"`
	Rate      string `json:"rate,omitempty"`
}
type WsReqParam struct {
	AccessToken string       `json:"access_token"`
	Version     string       `json:"version"`
	TtsParams   ReqTtsParams `json:"tts_params"`
}

type WsMsgData struct {
	Idx       int    `json:"idx"`
	AudioData string `json:"audio_data"`
	AudioType string `json:"audio_type"`
	Interval  string `json:"interval"`
	IntervalX string `json:"interval_x"`
	EndFlag   int    `json:"end_flag"`
}
type WsMsg struct {
	Code    int       `json:"code"`
	Message string    `json:"message"`
	TraceId string    `json:"trace_id"`
	Data    WsMsgData `json:"data"`
}

const grantType string = "client_credentials"

func GetToken(reqUrl, clientId, clientSecret string) (string, error) {
	// 超时时间:60秒
	client := &http.Client{Timeout: 60 * time.Second}
	urlParams := url.Values{}
	urlParams.Add("grant_type", grantType)
	urlParams.Add("client_id", clientId)
	urlParams.Add("client_secret", clientSecret)
	httpUrl := reqUrl
	httpUrl += "?"
	httpUrl += urlParams.Encode()
	fmt.Printf("httpUrl: %s\n\n", httpUrl)
	resp, err := client.Get(httpUrl)
	if err != nil {
		fmt.Printf("send http get token request failed, err: %s\n", err)
		return "", err
	}
	defer resp.Body.Close()
	result, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("http get token request, readall body failed, err: %s\n", err)
		return "", err
	}
	authInfo := AuthInfo{}
	err = json.Unmarshal(result, &authInfo)
	if err != nil {
		fmt.Printf("auth info json.Unmarshal err: %s \n", err)
		return "", err
	}
	if len(authInfo.AccessToken) <= 0 {
		return "", errors.New("access token is null")
	}
	fmt.Printf("get token success. info: %#v \n", authInfo)
	return authInfo.AccessToken, nil
}

func SendTts(urlStr string, reqParam WsReqParam) error {
	con, _, err := websocket.DefaultDialer.Dial(urlStr, nil)
	if err != nil {
		fmt.Printf("websocket dial failed. url: %s\n", urlStr)
		return err
	}
	defer con.Close()
	if strings.Contains(reqParam.TtsParams.VoiceName, "cc") {
		reqParam.TtsParams.Audiotype = "5"
	}
	err = con.WriteJSON(reqParam)
	if err != nil {
		fmt.Printf("websocket write json failed. url: %s\n", urlStr)
		return err
	}
	var f *os.File
	defer func() {
		if f != nil {
			_ = f.Close()
		}
	}()

	filename := reqParam.TtsParams.VoiceName + "_"
	filename += ".pcm"
	f, err = os.Create(filename)
	if err != nil {
		return err
	}
	fmt.Printf("output:\t%s\n", filename)
	writer := bufio.NewWriter(f)
	for {
		msg := WsMsg{}
		err = con.ReadJSON(&msg)
		if err != nil {
			fmt.Printf("websocket read json failed. url: %s\n", urlStr)
			return err
		}
		if msg.Code != 90000 {
			return fmt.Errorf("error_code %d, msg: %s", msg.Code, msg.Message)
		}
		fmt.Printf("index:\t%d\n", msg.Data.Idx)
		fmt.Printf("interval:\t%s\n", msg.Data.Interval)
		fmt.Printf("interval_x:\t%s\n", msg.Data.IntervalX)
		fmt.Printf("endflag:\t%d\n\n", msg.Data.EndFlag)
		if msg.Data.EndFlag == 1 {
			return nil
		}
		audioData, err := base64.StdEncoding.DecodeString(msg.Data.AudioData)
		if err != nil {
			return err
		}
		_, _ = writer.Write(audioData)
		_ = writer.Flush()
	}
	return nil
}

func main() {
	var (
		clientId, clientSecret, text, voiceName string
		audioType, rate                         int
		interval                                bool
	)
	flag.StringVar(&clientId, "cid", "", "client id")
	flag.StringVar(&clientSecret, "cs", "", "client secret")
	flag.StringVar(&text, "t", "标贝科技", "合成文本")
	flag.StringVar(&voiceName, "v", "Jingjing", "发音人")
	flag.IntVar(&audioType, "audiotype", 4, "audiotype")
	flag.IntVar(&rate, "rate", 0, "rate")
	flag.BoolVar(&interval, "interval", false, "interval")
	flag.Parse()
	if len(os.Args) < 2 {
		flag.Usage()
		return
	}
	if len(clientId) <= 0 || len(clientSecret) <= 0 || len(text) <= 0 || len(voiceName) <= 0 {
		fmt.Println("parameter error!!!")
		return
	}
	accessToken, err := GetToken("https://openapi.data-baker.com/oauth/2.0/token",
		clientId,
		clientSecret,
	)
	if err != nil {
		fmt.Println("get access token failed!!!! please check your client_id and client_secret.")
		return
	}
	base64Text := base64.StdEncoding.EncodeToString([]byte(text))
	param := WsReqParam{
		AccessToken: accessToken,
		Version:     "1.0",
		TtsParams: ReqTtsParams{
			Text:      base64Text,
			Language:  "ZH",
			Domain:    "1",
			VoiceName: voiceName,
			Audiotype: strconv.Itoa(audioType),
			Rate:      strconv.Itoa(rate),
		},
	}
	if interval {
		param.TtsParams.Interval = "1"
	}
	err = SendTts("wss://openapi.data-baker.com/tts/wsapi", param)
	if err != nil {
		fmt.Printf("send tts websocket request failed. err: %s \n", err.Error())
		return
	}
	fmt.Println("send websocket request success.")
}

C示例代码

代码地址:Github

JS示例代码

代码地址:Github

响应结果

  • 请求识别响应
  • 参数名称 类型 描述
    code int 错误码4xxxx表示客户端参数错误,5xxxx表示服务端内部错误,详见错误码
    message string 错误描述
    trace_id string 任务id
    {
          "code":40001,
          "message":" Invalid json data",
          "trace_id":" 1572234229176271"
    }
  • 成功响应
  • 参数名称 类型 描述
    code int 错误码4xxxx表示客户端参数错误,5xxxx表示服务端内部错误
    message string 错误描述
    trace_id string 任务id
    data object 合成音频片段
    idx int 包序号
    audio_data string base64编码后的音频数据,需要解码后使用
    audio_type string 音频格式
    interval string 音子边界信息
    end_flag int 结束标志:
    0:未结束
    1:结束
    interval_x string interval-info-x: L=1&T=1,L=1&T=2,L=1&T=1,L=1&T=2,L=1&T=5
    L表示语言种类,目前支持1:纯中文,5:中英混
    T表示interval类型,0:默认值,1:声母,2:韵母,3:儿化韵母,4:英文,5:#3静音
    {
          "code":90000,
          "message":"Success",
          "trace_id":" 1572234229176271"
          "data":{
            "idx":1,
            "audio_data":" P8EAPz/AQAGAPf/8v/n/wkAAwD//wsA7f/q/x",
            "audio_type":"audio/pcm",
            "interval":" h=0.083746&e=0.175807",
            "interval_x":"L=1&T=1,L=1&T=2"
            "end_flag":0
          }
    }

错误码

code 描述 处理建议
90000 返回音频数据
10001 access_token参数获取失败或未传输 检查参数
10002 domain参数值错误
10003 language参数错误
10004 voice_name参数错误
10005 audiotype参数错误
10006 rate参数错误
10007 idx错误
10008 single错误
10009 text参数错误
10010 文本太长
20000 获取资源错误
20001 断句失败
20002 分段数错误
20003 分段后的文本长度错误
20004 获取引擎链接错误
20005 RPC链接失败错误
20006 引擎内部错误
20007 操作redis错误
20008 音频编码错误
30000 鉴权错误(access_token值不正确或已经失效)
30001 并发错误
30002 内部配置错误
30003 json串解析错误
30004 获取url失败
30005 获取客户IP地址失败
30006 任务队列错误
40001 请求json不合法 检查参数
40002 请求缺失必须字段
40003 版本号错误
40004 字段值类型错误
40005 参数错误
50001 处理超时
50002 内部rpc调用失败
50004 其他内部错误