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

原创
09/28 08:45
阅读数 3.2K



本文为作者行舟客投稿,原文地址为https://yunxiaomeng.blog.csdn.net/article/details/108672415

 欢迎点赞!




背景

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

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

正文

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

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

但是当笔者用Google浏览器打卡后发现:浏览器禁止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不支持,但是控制台里面“万恶的报错”也没有了,会给你一个提示:总之就是我不给你播放。

所以,在除了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了。。。(因为它可以不经过用户主动触发而直接播放)


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



最后


  • 欢迎加我微信(winty230),拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

点个 在看支持我吧

本文分享自微信公众号 - 前端Q(luckyWinty)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部