Start · Sprachen · JavaScript · Referenz · AudioWorklet: port

AudioWorklet: port

Eigenschaft

Liefert einen <code>MessagePort</code>, über den der Haupt-Thread mit dem gesamten <code>AudioWorkletGlobalScope</code> eines Audio-Kontexts Nachrichten austauscht.

seit JavaScript Eingeschränkte Verfügbarkeit: nur neuere Browser-V Kategorie: webapi

Signatur

get AudioWorklet.prototype.port

Beschreibung

Die schreibgeschützte Eigenschaft port von AudioWorklet (erreichbar über audioContext.audioWorklet.port) gibt ein MessagePort-Objekt zurück. Es ist mit dem Gegenstück port im AudioWorkletGlobalScope verbunden, also dem globalen Gültigkeitsbereich, in dem die per addModule() geladenen Skripte auf dem Audio-Rendering-Thread laufen.

Wichtig ist der Unterschied zu AudioWorkletNode.port: Jeder Knoten hat einen eigenen Port, der mit genau einer AudioWorkletProcessor-Instanz verbunden ist. AudioWorklet.port dagegen gibt es einmal pro Audio-Kontext. Damit gibt es einen gemeinsamen Kanal für alle Prozessoren, etwa um geteilte Daten (Wavetables, Impulsantworten, SharedArrayBuffer, WebAssembly-Module) nur einmal zu übertragen oder um globale Einstellungen zu senden, noch bevor ein Knoten existiert.

Die Kommunikation läuft wie bei jedem MessagePort über postMessage() und das Ereignis message (bzw. onmessage). Die Daten werden per Structured Clone kopiert. Übertragbare Objekte wie ArrayBuffer oder weitere MessagePorts können per Transfer-Liste ohne Kopie übergeben werden.

Rückgabewert

Typ
MessagePort
Beschreibung
Der Port auf der Seite des Haupt-Threads. Sein Gegenstück ist die globale Eigenschaft port im AudioWorkletGlobalScope. Pro AudioWorklet wird immer dasselbe Objekt zurückgegeben.

Beispiele

Geteilte Konfiguration an den Worklet-Scope senden

// main.js
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('gain-processor.js');

// Globale Einstellung für alle Prozessoren
ctx.audioWorklet.port.postMessage({ type: 'config', masterGain: 0.5 });

const node = new AudioWorkletNode(ctx, 'gain-processor');
node.connect(ctx.destination);

// gain-processor.js (läuft im AudioWorkletGlobalScope)
let masterGain = 1;
port.onmessage = (event) => {
  if (event.data.type === 'config') {
    masterGain = event.data.masterGain;
  }
};

class GainProcessor extends AudioWorkletProcessor {
  process(inputs, outputs) {
    const input = inputs[0];
    const output = outputs[0];
    for (let ch = 0; ch < input.length; ch++) {
      for (let i = 0; i < input[ch].length; i++) {
        output[ch][i] = input[ch][i] * masterGain;
      }
    }
    return true;
  }
}
registerProcessor('gain-processor', GainProcessor);

Wavetable einmalig per Transfer übertragen

// main.js
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('wavetable.js');

const table = new Float32Array(2048).map((_, i) => Math.sin((2 * Math.PI * i) / 2048));
// Puffer wird übertragen statt kopiert
ctx.audioWorklet.port.postMessage({ type: 'wavetable', table }, [table.buffer]);
console.log(table.length);

// wavetable.js
globalThis.sharedTable = null;
port.addEventListener('message', ({ data }) => {
  if (data.type === 'wavetable') globalThis.sharedTable = data.table;
});
port.start(); // bei addEventListener nötig

Antworten aus dem Worklet-Scope empfangen

// main.js
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('status.js');

ctx.audioWorklet.port.onmessage = (event) => {
  console.log('Worklet meldet:', event.data);
};
ctx.audioWorklet.port.postMessage('ping');

// status.js
port.onmessage = (event) => {
  if (event.data === 'ping') {
    port.postMessage({ pong: true, sampleRate });
  }
};
Worklet meldet: { pong: true, sampleRate: 48000 }

// Wichtig · Fallstricke

  • Kompatibilität: AudioWorklet.port und AudioWorkletGlobalScope.port kamen erst spät in die Spezifikation und werden nur von neueren Browser-Versionen unterstützt. Prüfe die Unterstützung vorher, z. B. mit 'port' in ctx.audioWorklet, und nutze sonst AudioWorkletNode.port als Ausweichlösung.
  • Nicht mit AudioWorkletNode.port verwechseln: Dieser Port gehört zu einem einzelnen Prozessor, AudioWorklet.port zum gesamten Scope.
  • Nachrichten, die vor dem Setzen eines Handlers im Worklet-Skript ankommen, werden zwischengespeichert. Mit onmessage startet der Port automatisch, mit addEventListener() musst du port.start() selbst aufrufen.
  • Nachrichten kommen asynchron an, nicht synchron zum Audio-Takt. Wenn es auf genaues Timing ankommt, nutze AudioParam oder einen SharedArrayBuffer (setzt Cross-Origin-Isolation per COOP/COEP voraus).
  • Vermeide große oder häufige Nachrichten, denn Structured Clone kostet Zeit und erzeugt Speicherbereinigung auf dem Audio-Thread, was zu Aussetzern führen kann. Große Puffer besser per Transfer-Liste übergeben.
  • AudioWorklets funktionieren nur in sicheren Kontexten (HTTPS oder localhost).