探索js让你的网页“本身开口说话”




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

 欢迎点赞!web




背景

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

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

正文

原本嘛觉得是很简单的:就像通常给网页添加背景音乐,先动态建立一个audio元素,让其隐藏起来,而后用js添加一个event事件,并触发(事实上如今广泛认为的是:不能给网页添加背景音乐。但通过猜测和实践发现,也可经过下文第一种解决方式实现):后端

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

可是当笔者用Google浏览器打卡后发现:浏览器禁止audio/video自动播放了:autoplay被禁用了! 除非用户主动打开设置api

好吧听着就有点匪夷所思,通过笔者屡次测试得出——跨域

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

因此咱们能够换句话说:mp3等音频格式的autoplay被Google禁用了!promise

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

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


可是我仍是发现了文档中的一个“新”成员:web Audio API。虽然文档中没有描述什么相关原理,可是经过这段描述:image.png这让我忽然的就想到了HTML5的另外一个“大杀器”:canvas。他也是经过一个上下文对象context凌驾于浏览器图像/视频流之上。app

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不支持,可是控制台里面“万恶的报错”也没有了,会给你一个提示:image.png总之就是我不给你播放。

因此,在除了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了。。。(由于它能够不通过用户主动触发而直接播放)image.png


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



最后

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

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

image.png

相关文章
相关标签/搜索