AudioWorklet错误:DOMException:用户中止了请求。

17
我已在React中成功实例化了一个简单的AudioWorklet,并希望像Google示例中那样启动一个简单的振荡器。为了测试运行它,我正在渲染一个按钮,其onClick事件调用以下内容:
src/App.jsx:
userGesture(){
  //create a new AudioContext
  this.context = new AudioContext();

  //Add our Processor module to the AudioWorklet
  this.context.audioWorklet.addModule('worklet/processor.js').then(() => {

  //Create an oscillator and run it through the processor
  let oscillator = new OscillatorNode(this.context);
  let bypasser = new MyWorkletNode(this.context, 'my-worklet-processor');

  //Connect to the context's destination and start
  oscillator.connect(bypasser).connect(this.context.destination);
  oscillator.start();
  })
  .catch((e => console.log(e)))
}
问题在于,每次点击时,addModule方法都会返回以下错误:
DOMException: The user aborted a request.

我在Ubuntu v16.0.4上运行Chrome v66。

src/worklet/worklet-node.js:

 export default class MyWorkletNode extends window.AudioWorkletNode {
        constructor(context) {
          super(context, 'my-worklet-processor');
        }
      }

src/worklet/processor.js

class MyWorkletProcessor extends AudioWorkletProcessor {
    constructor() {
      super();
    }

    process(inputs, outputs) {
      let input = inputs[0];
      let output = outputs[0];
      for (let channel = 0; channel < output.length; ++channel) {
        output[channel].set(input[channel]);
      }


      return true;
    }
  }

  registerProcessor('my-worklet-processor', MyWorkletProcessor);

如果每个用户点击都调用了userGesture,那么你会不断地使用相同的名称注册相同的处理器。这是不允许的。虽然不理解错误信息。 - Raymond Toy
2
我刚遇到了同样的异常,原因是处理器文件中有语法错误。我已经检查了你的代码,没有发现任何错误。所以我不知道在你的情况下具体是什么原因导致了这个异常,但我会把这个评论留在这里,以防其他人也遇到同样的异常。 - filipovskii_off
我在使用较新的CSS Paint工作线程时遇到了完全相同的问题。如果我从github网站上拉取它们的示例,它可以正常工作。但是如果我将其托管在本地,则会出现错误。非常令人困惑。 - Dr_Derp
当模块文件路径错误时,它会抛出异常。 - Константин Ван
7个回答

14

我的代码是纯 JavaScript,不是 React,但是因为提供给 addModule 的路径不正确而遇到了同样的错误。在我的情况下,调用 addModule 的脚本和作为 addModule 参数提供的脚本都位于同一个目录("js")中。尽管如此,我仍然必须在路径中包含该目录才能消除错误:

...addModule('js/StreamTransmitter.js')...

我希望这可以帮到你。祝你好运!


谢谢!我在React的上下文中找到了答案,就是从公共目录中提供AudioWorkletProcessors。不好意思,我写了一篇完整的Medium文章;-) - spidercatnat

4

1
啊,你找到了我的文章,这个线程就在这里结束了 :) 不幸的是,HackerNoon失去了所有的要点。在Medium上查看相同的文章:https://medium.com/hackernoon/implementing-audioworklets-with-react-8a80a470474 - spidercatnat

4

如果其他人也遇到了这个神秘的错误,请不要自尊心作祟,检查以下内容:

  • 处理器没有任何错误。
  • 处理器使用正确的路径调用外部模块。
  • 外部模块没有任何错误。

如果通过"import"加载的外部模块存在错误,或者无法解析模块的路径(例如路径指向不存在的文件),则承诺将中止执行


在所有的答案中,这个是我发现最有用的一个 :) 我因为路径不正确而出现了错误。我忘记在移动文件时更改它,因为我习惯了VSCode自动更新ES模块导入。 - Ronald C

3
这似乎是Chromium模块加载器中的一个bug,它通过删除空格来解析worklet/processor.js文件,这会导致它在各个地方出现JavaScript语法错误,最终导致显示这个通用的、不太能解释的错误消息。 解决方案是使用以下方式提供工作线程处理器(例如,在您的情况下是worklet/processor.js):
Content-Type: application/javascript

或者
Content-Type: text/javascript

2
嗨John,感谢你的出色回答。在React中,代码应该在哪里添加Content-Type头呢? - spidercatnat

2
我也遇到了这个错误,但是是由于 Webpack 的问题造成的。
事实证明,Webpack 不支持工作线程(worklets),就像它支持 Web Workers 一样(参见此问题)
我建议使用 worker-url 与 webpack。
  1. 安装 worker-url
npm i --save-dev worker-url

更新你的webpack配置以包含WorkerUrl插件。
const WorkerUrlPlugin = require('worker-url/plugin');

module.exports = {
  // ...
  plugins: [new WorkerUrlPlugin()],
  // ...
};


使用WorkerUrl的方法如下:
import { WorkerUrl } from 'worker-url';

const workletUrl = new WorkerUrl(
  new URL('./random-noise-processor', import.meta.url),
  { name: 'worklet' },
);

await context.audioWorklet.addModule(workletUrl);

1

"DOMException: The user aborted a request." 出现时,意味着 AudioWorklet.addModule() 函数无法从您提供的路径或 URL 加载文件。请参考此 MDN 页面

api AudioWorklet.addModule() 需要 一个包含待添加模块的 JavaScript 文件的 URL 字符串

它可以是内部 URL,在这种情况下,它指向您的 public 文件夹,浏览器会在其中加载静态文件。例如 -> 如果 worklet 文件夹 在您的 React 应用程序的 public 目录 中,您可以按以下方式修改代码。

this.context.audioWorklet.addModule('worklet/processor.js')

在这种情况下,audioWorklet.addModule() 方法需要路径指向您的public folder。它也可以是一个外部URL,例如加载JS文件的Github存储库链接。

-1

修改:

this.context.audioWorklet.addModule('worklet/processor.js') 

使用

this.context.audioWorklet.addModule('../worklet/processor.js') 

对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接