Лучший способ вызвать функции модуля wasm в AudioWorkletProcessor?

#angular #web-audio-api #webassembly #audio-worklet

#угловатый #web-audio-api #веб-сборка #аудио-рабочий лист

Вопрос:

Я использую Angular для разработки веб-приложения для видеоконференцсвязи. Я пытаюсь вызвать некоторые функции wasm в моем AudioWorkletProcessor классе. Тем не менее, я совершенно зациклен на том, как передать модуль wasm в AudioWorkletProcessor , а затем вызвать эти функции. Я смог создать экземпляр модуля wasm из js-файла, сгенерированного из emcc (используя command: emcc test.cpp -s WASM=1 -s MODULARIZE=1 ), а затем попытался передать этот модуль через options.processorOptions параметр при создании AudioWorkletNode ; однако, похоже, что объекты функций не могут быть переданы, поскольку это дает DataCloneError . Есть ли лучший способ создания экземпляра модуля wasm и передачи его в процессор worklet, чтобы я мог использовать его функции?

Код audio.service.ts:

 import { Injectable } from '@angular/core';
import { AudioContext, AudioWorkletNode } from 'standardized-audio-context';
import * as Module from '../../../assets/worklet/a.out.js'; // a.out.js is file generated by emcc
declare const WebAssembly: any;

@Injectable()
export class AudioService {
  audioCtx = new AudioContext();

  constructor() {}

  async createNewSetting(track) {
    const srcNode = this.audioCtx.createMediaStreamTrackSource(track);
    const destNode = this.audioCtx.createMediaStreamDestination();

    await this.audioCtx.resume();
    await this.audioCtx.audioWorklet.addModule(
      './assets/worklet/spatial-processor.js'
    );

    // Instantiate the wasm module and put in path to file
    const wasm = await Module({ locateFile: function(s) { return 'assets/worklet/'   s; }});
    
    // Will throw DataCloneError
    const spatialNode = new AudioWorkletNode(
      this.audioCtx,
      'spatial-processor',
      { processorOptions: {
        compiledModule: wasm
      }}
    );

    // Connect the nodes
    srcNode.connect(spatialNode);
    spatialNode.connect(destNode);

    // Return the updated audio stream
    return destNode.stream.getTracks()[0];

  }
}
    
 

Ответ №1:

Передача экземпляра модуля WASM рабочему (или AudioWorklet) невозможна. Это работает только тогда, когда модуль WASM скомпилирован, но еще не создан. В MDN есть пример, который показывает, как это сделать с обычным рабочим, но он работает так же, как и при использовании processorOptions of an AudioWorkletProcessor .

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module#sending_a_compiled_module_to_a_worker

Идея состоит в том, чтобы использовать compileStreaming() в основном потоке и instantiate() в рабочем.

С другой стороны, также можно импортировать все непосредственно в AudioWorklet, как показано в этом примере. Однако я бы не рекомендовал этого делать, поскольку компиляция кода в аудиопотоке может привести к звуковому сбою.

https://googlechromelabs.github.io/web-audio-samples/audio-worklet/design-pattern/wasm/

Комментарии:

1. Ах, хорошо, это имеет смысл. Когда я выполняю метод compileStreaming () и создаю экземпляр () в worker, я получаю ошибку «Import # 0 module =»wasi_snapshot_preview1″: модуль не является объектом или функцией» ошибка. Я знаю, что js-файл, который создает emcc, заполняет функции в этом отсутствующем модуле, но поскольку я не могу использовать js-файл в процессоре, должен ли я сам заполнять отсутствующие методы модуля (через объект импорта, который передается в instantiate()), или есть болеевозможный способ приблизиться к этому?

2. Я не уверен, понял ли я ваш вопрос. Насколько я знаю, с emscripten это не так просто, потому что он создает некоторый код склеивания ( a.out.js file), который вызывает эти функции для вас. Это помогает?

3. Да, это помогает.