关键词: STATUS_ACCESS_VIOLATION AudioContext AudioWorkletNode audioWorklet addModule resume suspended createScriptProcessor

搞崩Chrome测试页:测试页地址

事件起因

我前些年GitHub开源的前端H5录音库:https://github.com/xiangyuecn/Recorder,提供了 mp3 wav ogg webm amr 格式支持,拥有丰富的音频可视化、变速变调处理、音频流播放、ASR语音识别等配套功能;搭配上强大的实时处理支持,可用于各种网页应用;最近打算尝试使用新浏览器特性升级一下,跟随上时代的发展。

不记得Chrome从哪个版本开始,对AudioContextcreateScriptProcessor方法调用时会在控制台中打印方法过时提醒:[Deprecation] The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead.

ScriptProcessor虽然被标记为过时了,但当前所有现代浏览器包括早期点的浏览器均得到了很好的支持,还没有在哪个浏览器上被正式的移除,Chrome的过这个时提醒就导致了经常有人问是不是要改用AudioWorklet了,目前的结论是还没有这个必要,因为单就获得录音数据这个场景而言,PC端两者并在性能上并没有区别,反而ScriptProcessor在移动端更具性能优势,这当然是后话了。

其实很早就想去升级提供AudioWorklet的支持,简单的过了一遍文档,预计的需要增加的代码量也不会很大(最后实际压缩后增加了2KB 这里查看这100来行的代码),不过拖到了前段时间才把代码给写了。

现象复现

在刚开始编写好测试的过程中,发现只要交互操作足够快,Chrome (版本:97)浏览器经常莫名其妙的崩溃(从来没有见过的现象),老版本Chrome80也会崩溃,错误代码:STATUS_ACCESS_VIOLATION,更老的66、70反而没有出现崩溃(得益于之前写的《自己制作Chrome便携版实现多版本共存》很方便测试),FireFox也不会崩溃。

经过反复测试,定位到问题:suspended状态下的AudioContext,在audioWorklet.addModule+构造AudioWorkletNode未完成时,同时进行resume调用,在恢复到running状态那一刻,浏览器崩溃了。其实根源还是在页面还没有用户交互过,就创建了AudioContext,这时的状态大概率是suspended(目的是浏览器禁止绕过没有用户操作自动声音播放)。

这些测试代码我已整合成了一个测试文件,点此进行测试,Chrome里面非常容易复现。

填坑处理

知道问题后,那解决就很简单了:

  • 方式一:等到有用户操作后再进行AudioContext的创建,此时能保证它一定是running状态;
  • 方式二:直接调用AudioContextresume方法,等到running后就没有崩溃的问题了。

由于我这个是开源库,没法决定开发者是否会等用户操作,所以方式二根据普遍适用性。

调用AudioContext.resume后,它返回的是一个Promise,在finally块(不管reject,小概率中的小概率崩溃可以忽略)中进行AudioWorklet的初始化,就是把原有的初始化代码套一层即可。

另外AudioContext.audioWorklet.addModule在本地file://协议下,Chrome竟然不支持加载Blob Url(FireFox没有这个问题),同样是Worker,WebWorker就没有这个毛病;最后改用data url来兼容Chrome:data:text/javascript;base64,......

最终结果

坑也填了,该测试的也测试了,满怀欣喜的发布了采用AudioWorklet录音的新版本。发布后,在手机上把玩把玩,咦,怎么好像短了几秒录音。。。

PC端、手机端反复的定时测试,最后发布声明:由于audioWorklet内部1秒375次回调,在移动端可能会有性能问题导致回调丢失录音变短,PC端无影响,暂不建议开启audioWorklet。

所以,又更新了一个版本,简单恢复了一下,库里面默认ScriptProcessor依旧是主力,可通过设置Recorder.ConnectEnableWorklet=true强制开启使用AudioWorklet

面向未来,如果以后哪个浏览器正式移除了ScriptProcessor,Recorder将会自动启用AudioWorklet,所以现在写的代码对将来会有很大意义,虽然目前有点鸡肋(感觉对AudioWorklet支持还是写早了,有点白写了的感觉),但意义还是很大的。

完整AudioWorklet实现代码,请移步阅读:recorder-core.js 第L157-L281行

【End】

几行代码把Chrome搞崩溃之:HTML5 MP3录音由ScriptProcessorNode升级成AudioWorkletNode采坑记的更多相关文章

  1. iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果

    8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...

  2. 5行代码怎么实现Hadoop的WordCount?

    初学编程的人,都知道hello world的含义,当你第一次从控制台里打印出了hello world,就意味着,你已经开始步入了编程的大千世界,这和第一个吃螃蟹的人的意义有点类似,虽然这样比喻并不恰当 ...

  3. 7 行代码搞崩溃 B 站,原因令人唏嘘!

    前不久,哔哩哔哩(一般常称为 B 站)发布了一篇文章<2021.07.13 我们是这样崩的>,详细回顾了他们在 2021.07.13 晚上全站崩溃约 3 小时的至暗时刻,以及万分紧张的故障 ...

  4. 30行代码搞定WCF并发性能测试

    [以下只是个人观点,欢迎交流] 30行代码搞定WCF并发性能 轻量级测试. 1. 调用并发测试接口 static void Main()         {               List< ...

  5. 几行c#代码,轻松搞定一个女大学生

    几行c#代码,轻松搞定一个女大学生 的作业... 哈哈,标题党了哈,但是是真的,在外面敲代码,想赚点外快,接到了一个学生的期末考试,是一个天气预报的程序.程序并不难. 看到这个需求第一个想法就是只要找 ...

  6. [Unity Editor]10行代码搞定Hierarchy排序

    在日常的工作和研究中,当给我们的场景摆放过多的物件的时候,Hierarchy面板就会变得杂乱不堪.比如这样:    过多的层次结构充斥在里面,根层的物件毫无序列可言,整个层次面板显示非常的杂乱不堪,如 ...

  7. 10行代码搞定移动web端自定义tap事件

    发发牢骚 移动web端里摸爬滚打这么久踩了不少坑,有一定移动web端经验的同学一定被click困扰过.我也不列外.一路走来被虐的不行,fastclick.touchend.iscroll什么的都用过, ...

  8. BaseHttpListActivity,几行代码搞定Android Http列表请求、加载和缓存

    Android开发中,向服务器请求一个列表并显示是非常常见的需求,但实现起来比较麻烦,代码繁杂. 随着应用的更新迭代,这种需求越来越多,我渐渐发现了实现这种需求的代码的共同点. 于是我将Activit ...

  9. python爬煎蛋妹子图--20多行代码搞定煎蛋妹子图库

    如果说一个人够无聊的话... 就会做一些十分美(wei)丽(suo)的事情啦哈哈哈... 好的,话不多说,进入正题. 正如标题所示,我们今天的目标很简单: 代码要少,妹子要好. 步骤如下: 1. 首先 ...

随机推荐

  1. kibana 对es的简单操作。

    一.查询和查看. #1.查询所有的数据 GET _search { "query": { "match_all":{} } } #2. 查看ES集群的健康状态 ...

  2. STL priority_queue 优先队列 小记

    今天做题发现一个很有趣的地方,竟然还是头一次发现,唉,还是太菜了. 做图论用STL里的priority_queue去优化prim,由于特殊需求,我需要记录生成树中是用的哪些边. 于是,我定义的优先队列 ...

  3. Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)

    基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...

  4. RedHat Linux 忘记密码

    一.无法进入系统 在虚拟机开机3秒时按e 选择第二个选项带有quite的那个 进入界面后,在quite后,空格+single 进入单用户模式 然后输入passwd +账号(要修改的账号) 输入新的密码 ...

  5. UIKit绘图演练

    一般使用UIKit给我们提供的绘图来绘制一些文字,图片这些东西.     UIKit给我们提供画图的方法底层也是分为四步.所以也必须在drawRect方法当中去写.     1.如何画文字?      ...

  6. js 计算中英文混合字符串长度

    转载请注明来源:https://www.cnblogs.com/hookjc/ function isChinese(str) {    var lst = /[u00-uFF]/;          ...

  7. mybatis的一对多(collection)

    使用图解: 低效率查询: 高效率查询: 1 查询用联合查询 2<collection 里面不写column

  8. 注解的使用、拦截器使用、AOP切面使用

    Java 自定义注解及使用场景 转载: https://www.jianshu.com/p/a7bedc771204 Java自定义注解一般使用场景为:自定义注解+拦截器或者AOP,使用自定义注解来自 ...

  9. java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

    一.JDBC的概述 1.JDBC为访问不同的数据薛是供了统一的接口,为使用者屏蔽了细节问题.2. Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作 ...

  10. 有手就行8——项目构建细节3-Jenkins的参数化构建

    有手就行8--项目构建细节3-Jenkins的参数化构建 有时在项目构建的过程中,我们需要根据用户的输入动态传入一些参数,从而影响整个构建结果,这时  我们可以使用参数化构建. Jenkins支持非常 ...