对接百度api之语音合成

前言

个人觉得对接百度api相对来说是比较容易的,就是先获取token,再去调应用接口。
在对接语音合成的时候,百度api返回的是音频的流文件。
需求是要用js播放,看了好多人的博客,大多都是后端生成MP3文件,将文件链接返回给页面,
但是我们希望的是不生成MP3文件,直接用js读取音频流。
文章有什么不正确的地方请留意,谢谢~

关于创建应用,获取token请参考 对接百度api之银行卡识别

简介

百度语音合成服务,基于HTTP请求的REST API接口,将文本转换为可以播放的音频文件。

  • 多音字可以通过标注自行定义发音。格式如:重(chong2)报集团。

  • 目前只有中英文混合这一种语言,优先中文发音。示例: " I bought 3 books” 发音 “three”; “ 3 books
    are bought” 发音 “三”; “我们买了 3 books” 发音“三”

请求方式和参数

上传参数

参数可需描述
tex必填合成的文本,使用UTF-8编码。小于2048个中文字或者英文数字。(文本在百度服务器内转换为GBK后,长度必须小于4096字节)
tok必填开放平台获取到的开发者access_token(见上面的“鉴权认证机制”段落)
cuid必填用户唯一标识,用来计算UV值。建议填写能区分用户的机器 MAC 地址或 IMEI 码,长度为60字符以内
ctp必填客户端类型选择,web端填写固定值1
lan必填固定值zh。语言选择,目前只有中英文混合模式,填写固定值zh
spd选填语速,取值0-15,默认为5中语速
pit选填音调,取值0-15,默认为5中语调
vol选填音量,取值0-15,默认为5中音量
per(基础音库)选填度小宇=1,度小美=0,度逍遥=3,度丫丫=4
per(精品音库)选填度博文=106,度小童=110,度小萌=111,度米朵=103,度小娇=5
aue选填3为mp3格式(默认); 4为pcm-16k;5为pcm-8k;6为wav(内容同pcm-16k); 注意aue=4或者6是语音识别要求的格式,但是音频内容不是语音识别要求的自然人发音,所以识别效果会受影响。

POST调用方式(推荐)

返回

需要根据 Content-Type的头部来确定是否服务端合成成功。

如果合成成功,返回的Content-Type以“audio”开头

aue =3 ,返回为二进制mp3文件,具体header信息 Content-Type: audio/mp3;
aue =4 ,返回为二进制pcm文件,具体header信息 Content-Type:audio/basic;codec=pcm;rate=16000;channel=1
aue =5 ,返回为二进制pcm文件,具体header信息 Content-Type:audio/basic;codec=pcm;rate=8000;channel=1
aue =6 ,返回为二进制wav文件,具体header信息 Content-Type: audio/wav;

如果合成出现错误,则会返回json文本,具体header信息为:Content-Type: application/json。其中sn字段主要用于DEBUG追查问题,如果出现问题,可以提供sn帮助确认问题。

错误示例:

{“err_no”:500,“err_msg”:“notsupport.”,“sn”:“abcdefgh”,“idx”:1}

百度语音合成浏览器跨域访问示例

在这里插入图片描述

直接访问这个html,如下:

在这里插入图片描述
点击这里的合成按钮:
在这里插入图片描述
点击播放即可。

合成方法,相应的参数可自行设置。
在这里插入图片描述响应成功后的处理:
在这里插入图片描述

所需的js文件

baidu_tts_cors.js

/**
 * 浏览器调用语音合成接口
 * @param {Object} param 百度语音合成接口参数
 * 请参考 https://ai.baidu.com/docs#/TTS-API/41ac79a6
 * @param {Object} options 跨域调用api参数
 *           timeout {number} 超时时间 默认不设置为60秒
 *           volume {number} audio控件音量,范围 0-1
 *           hidden {boolean} 是否隐藏audio控件
 *           autoDestory {boolean} 播放音频完毕后是否自动删除控件
 *           onInit {Function} 创建完audio控件后调用
 *           onSuccess {Function} 远程语音合成完成,并且返回音频文件后调用
 *           onError {Function}  远程语音合成完成,并且返回错误字符串后调用
 *           onTimeout {Function} 超时后调用,默认超时时间为60秒
 */
function btts(param, options) {
    var url = 'http://tsn.baidu.com/text2audio';
    var opt = options || {};
    var p = param || {};

    // 如果浏览器支持,可以设置autoplay,但是不能兼容所有浏览器
    var audio = document.createElement('audio');
    if (opt.autoplay) {
        audio.setAttribute('autoplay', 'autoplay');
    }

    // 隐藏控制栏
    if (!opt.hidden) {
        audio.setAttribute('controls', 'controls');
    } else {
        audio.style.display = 'none';
    }

    // 设置音量
    if (typeof opt.volume !== 'undefined') {
        audio.volume = opt.volume;
    }

    // 调用onInit回调
    isFunction(opt.onInit) && opt.onInit(audio);

    // 默认超时时间60秒
    var DEFAULT_TIMEOUT = 60000;
    var timeout = opt.timeout || DEFAULT_TIMEOUT;

    // 创建XMLHttpRequest对象
    var xhr = new XMLHttpRequest();
    xhr.open('POST', url);

    // 创建form参数
    var data = {};
    for (var p in param) {
        data[p] = param[p]
    }

    // 赋值预定义参数
    data.cuid = data.cuid || data.tok;
    data.ctp = 1;
    data.lan = data.lan || 'zh';
    data.aue = data.aue || 3;

    // 序列化参数列表
    var fd = [];
    for(var k in data) {
        fd.push(k + '=' + encodeURIComponent(data[k]));
    }

    // 用来处理blob数据
    var frd = new FileReader();
    xhr.responseType = 'blob';
    xhr.send(fd.join('&'));

    // 用timeout可以更兼容的处理兼容超时
    var timer = setTimeout(function(){
        xhr.abort();
        isFunction(opt.onTimeout) && opt.onTimeout();
    }, timeout);

    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            clearTimeout(timer);
            if (xhr.status == 200) {
                if (xhr.response.type === 'audio/mp3') {

                    // 在body元素下apppend音频控件
                    document.body.appendChild(audio);

                    audio.setAttribute('src', URL.createObjectURL(xhr.response));

                    // autoDestory设置则播放完后移除audio的dom对象
                    if (opt.autoDestory) {
                        audio.onended = function() {
                            document.body.removeChild(audio);
                        }
                    }

                    isFunction(opt.onSuccess) && opt.onSuccess(audio);
                }

                // 用来处理错误
                if (xhr.response.type === 'application/json') {
                    frd.onload = function(){
                        var text = frd.result;
                        isFunction(opt.onError) && opt.onError(text);
                    };
                    frd.readAsText(xhr.response);
                }
            }
        }
    }

    // 判断是否是函数
    function isFunction(obj) {
        if (Object.prototype.toString.call(obj) === '[object Function]') {
            return true;
        }
        return false;
    }
}

demo.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <script type="text/javascript" src="baidu_tts_cors.js"></script>
  <script type="text/javascript">

    // 初始化变量
    var audio = null;
    var playBtn = null;

    // dom加载完毕回调后注册按钮对象
    ready(function() {
        playBtn = document.getElementById('playBtn');
    });

    // 合成按钮
    function tts() {
        let text = document.getElementById('text').value;
        playBtn.innerText = '准备中';

        // 调用语音合成接口
        // 参数含义请参考 https://ai.baidu.com/docs#/TTS-API/41ac79a6
        audio = btts({
            tex: text,
            tok: '24.60645ec713f5163935cf5d7037f71d5d.2592000.1568961325.282335-15876292',
            spd: 5,
            pit: 5,
            vol: 15,
            per: 4
        }, {
            volume: 0.3,
            autoDestory: true,
            timeout: 10000,
            hidden: false,
            onInit: function (htmlAudioElement) {

            },
            onSuccess: function(htmlAudioElement) {
                audio = htmlAudioElement;
                playBtn.innerText = '播放';
            },
            onError: function(text) {
                alert(text)
            },
            onTimeout: function () {
                alert('timeout')
            }
        });
    }

    // 播放按钮
    function play() {
        if (audio === null) {
            alert('请先点击合成')
        } else {
            audio.play();
        }
    }

    // 暂停按钮
    function pause() {
        if (audio === null) {
            alert('请先点击合成')
        } else {
            audio.pause();
        }
    }

    // 取消按钮
    function cancel() {
        if (audio === null) {
            alert('请先点击合成')
        } else {
            audio.pause();
            document.body.removeChild(audio);
            audio = null;
            playBtn.innerText = '准备中';
        }
    }

    // dom加载完毕回调
    function ready(callback){
        var doc = document;
        if (doc.addEventListener) {
            doc.addEventListener('DOMContentLoaded', function() {
                callback();
            }, false);
        } else if (doc.attachEvent) {
            doc.attachEvent('onreadystatechange', function() {
                if (doc.readyState === 'complete') {
                    callback();
                }
            });
        }
    }
  </script>
</head>
<body>
    <div>
        <input type="text" id='text' value='百度语音合成' style='width: 500px;'>
        <button onclick='tts()'>合成</button>
        <button onclick='play()' id='playBtn'>准备中</button>
        <button onclick='pause()'>暂停</button>
        <button onclick='cancel()'>取消</button>
    </div>
</body>
</html>

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值