Start · Sprachen · JavaScript · Referenz · AudioWorkletGlobalScope: port

AudioWorkletGlobalScope: port

Eigenschaft

Schreibgeschützter <code>MessagePort</code> im globalen Gültigkeitsbereich eines AudioWorklets für den Nachrichtenaustausch mit <code>AudioWorklet.port</code> im Hauptthread.

seit JavaScript Web Audio API (neuere Ergänzung) – eingeschränkte Kategorie: webapi

Signatur

AudioWorkletGlobalScope.port

Beschreibung

Die schreibgeschützte Eigenschaft port des Interfaces AudioWorkletGlobalScope gibt ein MessagePort-Objekt zurück. Es ist das Gegenstück zu AudioWorklet.port im Hauptthread (audioContext.audioWorklet.port). Beide Enden bilden zusammen einen Kanal, über den Hauptthread und Audio-Rendering-Thread Nachrichten austauschen können.

Wichtig ist der Unterschied zu AudioWorkletProcessor.port: Den Port eines Prozessors gibt es einmal pro AudioWorkletNode, und er verbindet genau diesen Knoten mit seinem Prozessor. Der Port des globalen Gültigkeitsbereichs gibt es dagegen nur einmal pro BaseAudioContext, und alle Prozessoren in diesem Gültigkeitsbereich teilen ihn sich. Er eignet sich deshalb für Daten, die alle Prozessoren gemeinsam nutzen: kompilierte WebAssembly-Module, Lookup-Tabellen, Impulsantworten, globale Einstellungen oder SharedArrayBuffer-Speicher.

Im Modulcode des Worklets greift man direkt über den globalen Namen port auf die Eigenschaft zu, denn globalThis ist dort der AudioWorkletGlobalScope. Nachrichten verschickt man mit port.postMessage(), und man empfängt sie über port.onmessage oder port.addEventListener("message", …). Bei addEventListener muss man zusätzlich port.start() aufrufen.

Rückgabewert

Typ
MessagePort
Beschreibung
Der MessagePort auf der Worklet-Seite des Kanals. Er ist mit AudioWorklet.port im Hauptthread verbunden, und innerhalb des Gültigkeitsbereichs wird immer dasselbe Objekt zurückgegeben.

Beispiele

Hauptthread: globale Konfiguration an das Worklet senden

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

// Antworten aus dem globalen Gültigkeitsbereich empfangen
ctx.audioWorklet.port.onmessage = (event) => {
  console.log("Worklet meldet:", event.data);
};

// Eine Einstellung, die für alle Prozessoren gilt
ctx.audioWorklet.port.postMessage({ type: "setGain", value: 0.5 });

const nodeA = new AudioWorkletNode(ctx, "shared-gain");
const nodeB = new AudioWorkletNode(ctx, "shared-gain");
nodeA.connect(ctx.destination);
nodeB.connect(ctx.destination);
Worklet meldet: { type: 'ack', gain: 0.5 }

Worklet: gemeinsamen Zustand über den globalen port pflegen

// shared-processor.js (läuft im AudioWorkletGlobalScope)
const shared = { gain: 1 };

port.onmessage = (event) => {
  const { type, value } = event.data;
  if (type === "setGain") {
    shared.gain = value;
    port.postMessage({ type: "ack", gain: shared.gain });
  }
};

class SharedGainProcessor extends AudioWorkletProcessor {
  process(inputs, outputs) {
    const input = inputs[0];
    const output = outputs[0];
    for (let ch = 0; ch < output.length; ch++) {
      const inCh = input[ch];
      const outCh = output[ch];
      if (!inCh) continue;
      for (let i = 0; i < outCh.length; i++) {
        outCh[i] = inCh[i] * shared.gain; // alle Instanzen lesen denselben Wert
      }
    }
    return true;
  }
}

registerProcessor("shared-gain", SharedGainProcessor);

WebAssembly-Modul einmalig für alle Prozessoren bereitstellen

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

const bytes = await (await fetch("dsp.wasm")).arrayBuffer();
const module = await WebAssembly.compile(bytes);

// WebAssembly.Module ist strukturiert klonbar
ctx.audioWorklet.port.postMessage({ type: "wasm", module });

// wasm-processor.js
// let wasmModule = null;
// port.onmessage = ({ data }) => {
//   if (data.type === "wasm") wasmModule = data.module;
// };
// Prozessoren instanziieren später mit
// new WebAssembly.Instance(wasmModule, imports)

// Wichtig · Fallstricke

  • Browser-Unterstützung: AudioWorkletGlobalScope.port und AudioWorklet.port sind erst spät in die Spezifikation aufgenommen worden und noch nicht überall verfügbar. Prüfe das vorher, z. B. mit "port" in ctx.audioWorklet. Als Ausweichlösung kann man Daten über AudioWorkletProcessor.port oder processorOptions pro Knoten übergeben.
  • Nicht verwechseln mit AudioWorkletProcessor.port (this.port im Prozessor). Den gibt es einmal pro Knoten, den globalen port dagegen nur einmal pro Audio-Kontext.
  • Echtzeit-Thread: Aufwendige Arbeit in onmessage, z. B. große Kopien oder das Kompilieren von WebAssembly, kann das Audio-Rendering stören und Aussetzer verursachen. Große Puffer überträgt man besser als Transferable (postMessage(data, [buffer])). Für häufige Parameteränderungen eignen sich AudioParam oder SharedArrayBuffer besser.
  • Nachrichten kommen asynchron an. Ein process()-Aufruf kann also noch mit dem alten Zustand laufen, bis die Nachricht verarbeitet ist.
  • Wer addEventListener("message", …) statt onmessage nutzt, muss port.start() aufrufen, sonst kommen keine Nachrichten an.
  • SharedArrayBuffer funktioniert nur in einem isolierten Kontext (crossOriginIsolated, also mit COOP/COEP-Headern).