探索js让你的网页“自己开口说话”

最近一直在研究音视频流,正好想要做一个“有声提示”,增强页面交互和用户体验的功能。(以后打算引入前端AI,让整个页面真正实现“语音控制”,嘿嘿)。
这一想,顺便就想到了让一众网友为难的“网页自动播放音视频”。

不说废话,实现过程中倒是遇到了一点小问题:


本来嘛以为是很简单的:就像一般给网页添加背景音乐,先动态创建一个audio元素,让其隐藏起来,然后用js添加一个event事件,并触发(事实上现在普遍认为的是:不能给网页添加背景音乐。但经过猜想和实践发现,也可通过下文第一种解决方式实现):

浏览器厂商为了用户体验考虑禁止自动播放出发点是好的,but为什么要做这么绝情呢?
有一句非常著名的话:“不要试图让用户做自己不熟悉的操作”,难道就不能在 DOMContentLoaded 或者 document.readyState==="complete" 前让渲染线程暂停并给出一个显式提示让用户去抉择?你就在console里报个错是几个意思

let event = new MouseEvent("click"); // 创建一个单击事件
//给触发元素添加属性或者回调事件
//比如:a.download = xxx  /  div.οnclick=function(){}
触发元素.dispatchEvent(event); // 触发单击事件

但是这时候发现:浏览器现在全面禁止audio/video自动播放了:autoplay被禁用了! 除非用户主动打开设置

好吧听着就有点匪夷所思,准确地说是——

  1. 在controls属性存在时video允许autoplay控制自动播放,controls不存在时其autoplay属性不起作用;(Google)
  2. audio元素的autoplay属性永远不起作用(必须用户手动触发);(Google和Firefox)
  3. video元素是支持source兼容的!但是如果source中type为音频相关格式,那么autoplay大概率也不起作用;(Google和Firefox等)
  4. 文档中要求的“手动触发”很严格——按道理讲上面代码创建一个鼠标事件其意义和用户手动按下鼠标按钮是一样的,但是,浏览器不支持!

所以我们可以换句话说:mp3等音频格式的autoplay被Google禁用了!

没有办法,我只能将目光移向“元素click事件”,后来想来是我多想了——因为上面第四点的缘故,任何非用户手动操作的“动作”都会被浏览器禁止。

Google浏览器为其取了一个很有意义的名字 —— 自动播放阻止。


但是我还是发现了文档中的一个“新”成员:web Audio API。虽然文档中没有描述什么相关原理,但是通过这段描述:
好吧,是一张图片
这让我突然的就想到了HTML5的另一个“大杀器”:canvas。他也是通过一个上下文对象context凌驾于浏览器图像/视频流之上。

web audio api怎么说呢,感觉至少目前对大多数人用处真不大——文档中&被广大开发者发掘的各种骚操作canvas能做的都用canvas了,canvas不能做的对绝大多数开发者来说也不重要。

顺着这个思路,我想到了“创建一个音轨上下文,在其中用 createBufferSource() 方法用于创建一个新的 AudioBufferSourceNode接口—— 该接口可以通过 AudioBuffer对象 来播放音频数据,以突破浏览器限制”,AudioBuffer对象怎么获取?
web audio API为了解决音频源的问题,提出了“向音频url发送一个请求,将数据以arraybuffer返回,再解码得到元数据”这样看似复杂的方法,具体过程是这样的:

方法使用XHR加载一个音轨,设置请求的responsetype为ArrayBuffer使它返回一个arraybuffer数据,然后存储在audioData变量中。然后我们将这个arraybuffer数据置于decodeAudioData()方法中使用,当成功解码PCM Data后通过promise回调返回, 将返回的结果通过AudioContext.createBufferSource()接口进行处理并获得一个AudioBufferSourceNode,,将源连接至AudioContext.destination形成一个完整的音频流。

var context = new (window.AudioContext || window.webkitAudioContext)();
var soundBuffer = null;

function loadSound(url) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';

    request.onload = function() {
        context.decodeAudioData(request.response).then((buffer)=>{
            soundBuffer = buffer;
            playSound(soundBuffer);
        });
    };
    request.send();
}

function playSound(buffer) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    source[source.start?"start":"noteOn"](0);
}
//你也可以将init放在某个按钮触发事件上
window.addEventListener('DOMContentLoaded', init, false);

function init() {
    try {
        var url = "audio/1.mp3";
        loadSound(url);
    } catch (e) {
        alert('你的浏览器不支持Web Audio API');
    }
}

这里有两个注意点:

  1. 倒数第六行url那里如果是个音频的话最好还是手动下载到本地,不然极有可能涉及到跨域问题
  2. 如果是要“语音提示某一段话”,则可以为代码中 init() 函数增加txt参数,并调用百度转化接口,将文字先用encodeURI API转化为uri格式,再接入百度接口 var url = "http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=" + encodeURI('这里是字符串文本'); 转化为url链接

这段代码很神奇:google不支持,但是控制台里面“万恶的报错”也没有了,会给你一个提示:
define
总之就是我不给你播放。

所以,在除了Google的其余浏览器中,建议将上面的API和下面这段HTML代码一起写上:

<video controls autoplay style="display:none;">   /** 或者将controls和style都去掉 */
	<source src="这里写要播放的音频路径,如:http://m10.music.126.net/20200926133756/cba79f37e90871df07cd582befe27723/ymusic/obj/w5zDlMODwrDDiGjCn8Ky/2920523350/fd2a/c111/aae2/5542b627692d3df8d63bbaeb1c73711a.mp3" type="audio/mp3"></source>
</video>

然后你应该就可以听到美妙动听的背景音了!

Firefox和Edge虽然禁掉了autoplay,但是它也是支持AudioContext API的!
Google中禁止了一切不符合规范的API,而且可能是因为某些不知名原因,上面这段HTML代码在Google中是时而可以时而不行的,就很迷惑。。。


补充
其实这个API最大的作用是用于音频可视化领域——它有一个函数是这样的:createAnalyser() 用来创建一个音域可视化对象,可以将它连接到context流上:

var gainNode=context[context.createGain?"createGain":"createGainNode"]();
gainNode.connect(context.destination);
//操作完上一步后,我们已经将音域加载到context流上,以后的操作就可以直接连接这个音域对象
var analyser=context.createAnalyser();
analyser.fftSize=512;
analyser.connect(gainNode);

发现浏览器中有了部分实现的相关API——它曾经一直在逃避浏览器音频播放政策:

function speak(sentence,pitch,volume) {   //使用时调用这个函数即可
    const utterance = new SpeechSynthesisUtterance(sentence);
    //音调
    utterance.pitch = pitch;
    //音量
    utterance.volume = volume;
    window.speechSynthesis.speak(utterance)
}

参数 sentence 是一个字符串格式文本。

只要调用了这个函数并传入参数,你就能在浏览器中听到动听的、梦寐以求的声音了!(还是个女声,嘿嘿嘿)
目前,
Chrome70已经废弃这个API了。。。(因为它可以不经过用户主动触发而直接播放)
speak-API


当然还有稳妥一些的做法,也是个让人比较眼前一亮的操作:
是MDN文档中提到的 Feature-Policy 头——HTTP头信息,可设置自动播放相关:这个属性是给后端用的:在response中设置header!

  • 33
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恪愚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值