当前位置: 首页 > Web前端 > HTML

几行代码让Chrome崩溃:HTML5MP3录音升级为AudioWorkletNode挖矿笔记

时间:2023-03-28 17:04:09 HTML

Keywords:STATUS_ACCESS_VIOLATIONAudioContextAudioWorkletNodeaudioWorkletaddModuleresumesuspendedcreateScriptProcessorcrashedChrometestpage:测试页面地址事件原因在GitHub上开源了一些多年前前端H5录音库:https://github.com/xiangyuecn/Recorder,提供mp3wavoggwebmamr格式支持,具有丰富的音频可视化、变速变音处理、音频流播放、ASR语音识别等辅助功能;具有强大的实时处理支持,可用于各种Web应用;最近,我打算尝试使用新的浏览器功能来升级并跟随前一个时代的发展。我不记得哪个版本的Chrome启动了。在调用AudioContext的createScriptProcessor方法时,会在控制台打印方法过时提示:[Deprecation]TheScriptProcessorNodeisdeprecated。请改用AudioWorkletNode。尽管ScriptProcessor被标记为已过时,但包括早期浏览器在内的所有现代浏览器都得到了很好的支持,并且尚未在任何浏览器上正式删除。Chrome对这个时间的提醒导致人们经常询问是否切换到AudioWorklet。目前的结论是没有必要,因为就获取录音数据的场景而言,两者在PC端的性能上没有区别。相反,ScriptProcessor在移动端更为重要。当然,性能优势是另一回事。其实很早就想升级提供AudioWorklet支持了。简单看了下文档,估计需要增加的代码量不会很大(最后实际压缩后实际增加了2KB,这里查看100行代码),但是代码是前段时间写的。现象重现在一开始写好测试的过程中,发现只要交互操作速度足够快,Chrome(版本:97)浏览器经常会莫名其妙的崩溃(以前从未出现过的现象),并且老版本的Chrome80也会崩溃,错误代码:STATUS_ACCESS_VIOLATION,老的66和70没有崩溃(感谢之前写的《自己制作Chrome便携版实现多版本共存》,测试起来很方便),FireFox不会崩溃。经过反复测试,问题定位:处于挂起状态的AudioContext,当audioWorklet.addModule+构造AudioWorkletNode未完成时,同时调用resume,回到运行状态时浏览器崩溃。其实根本原因是AudioContext是在页面没有用户交互的情况下创建的,此时的状态很可能是暂停(目的是浏览器禁止绕过没有用户操作的自动播放声音)。我已经将这些测试代码整合成一个测试文件,点击这里进行测试,在Chrome中重现非常容易。知道问题后,解决方法很简单:方法一:等到有用户操作后再创建AudioContext,此时可以保证一定是运行状态;方法二:直接调用AudioContext的resume方法,等到它运行起来就没有闪退的问题了。由于这是一个开源库,我无法决定开发者是否会等待用户操作,所以第二种方法是基于普遍适用性。AudioContext.resume调用后,返回一个Promise,并在finally块中初始化AudioWorklet(不考虑reject,小概率crash的小概率可以忽略),即把原来的初始化代码在一层。另外,本地file://协议下的AudioContext.audioWorklet.addModule,Chrome不支持加载BlobUrl(FireFox没有这个问题),同样的Worker,WebWorker没有这个问题;最后使用dataurl兼容Chrome:data:text/javascript;base64,...最终结果填好了,测试也通过了,愉快的发布了一个使用AudioWorklet录音的新版本。放完之后在手机上摆弄了一下,咦,怎么录音好像少了几秒。..在PC端和移动端反复计时测试,最后发表声明:由于audioWorklet内部每秒375次回调,在移动端可能存在性能问题,可能会导致回调丢失,录音变短.PC端无影响,暂时不建议启用audioWorklet。于是又更新了一个版本,索性恢复了。库中默认的ScriptProcessor依然是主力。您可以通过设置Recorder.ConnectEnableWorklet=true来强制使用AudioWorklet。面向未来,如果以后有哪个浏览器正式去掉ScriptProcessor,Recorder会自动启用AudioWorklet,所以现在写的代码对以后会有很大的意义,虽然目前有点鸡肋(感觉对AudioWorklet的支持是还是写早了,有点白感觉是自己写的),但意义还是很大的。完整的AudioWorklet实现代码请一步步阅读:recorder-core.js的L157-L281行。【结尾】