Signatur
Beschreibung
AudioContext ist der zentrale Einstiegspunkt der Web Audio API. Ein Kontext verwaltet einen Graphen aus Audioknoten, also Quellen (z. B. OscillatorNode, AudioBufferSourceNode, MediaElementAudioSourceNode), Effekten (z. B. GainNode, BiquadFilterNode) und Analyse-Knoten (AnalyserNode). Diese Knoten verbindest du mit connect() und leitest das Ergebnis am Ende auf context.destination, also auf die Lautsprecher.
Ein AudioContext eignet sich für Spiele, Synthesizer, Visualisierungen, Echtzeit-Effekte auf Mikrofonsignale und für genau getimte Wiedergabe. Alle Zeitangaben beziehen sich auf die hochauflösende Uhr currentTime. Damit lassen sich Ereignisse sampelgenau planen, was mit setTimeout nicht möglich ist.
Wichtige Mitglieder (teils von BaseAudioContext geerbt): state ("suspended", "running", "closed"), sampleRate, currentTime, destination, baseLatency, outputLatency sowie die Methoden resume(), suspend(), close(), decodeAudioData(), getOutputTimestamp(), createMediaElementSource(), createMediaStreamSource() und createMediaStreamDestination(). Zum Offline-Rendern ohne Ausgabegerät gibt es OfflineAudioContext.
In der Regel reicht ein einziger Kontext pro Seite. Er belegt Systemressourcen und sollte daher wiederverwendet und nicht mehr benötigt mit close() freigegeben werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | AudioContextOptions | {} | Optionales Konfigurationsobjekt für den Konstruktor new AudioContext(options). |
| $options.latencyHint | "interactive" | "balanced" | "playback" | number | "interactive" | Gewünschte Latenz: "interactive" für möglichst geringe Latenz, "playback" für stromsparende Wiedergabe oder eine Zahl in Sekunden. |
| $options.sampleRate | number | Abtastrate des Ausgabegeräts | Abtastrate in Hz (z. B. 44100 oder 48000). Ohne Angabe gilt die Rate des Geräts. |
| $options.sinkId | string | { type: "none" } | "" (Standardgerät) | ID des Audio-Ausgabegeräts oder { type: "none" } für eine Verarbeitung ohne Ausgabe. Wird noch nicht von allen Browsern unterstützt. |
Rückgabewert
state ist "running" oder "suspended", falls die Autoplay-Richtlinie noch keine Nutzerinteraktion erkannt hat.Beispiele
Kontext bei Nutzerinteraktion erzeugen und Ton abspielen
let ctx;
document.querySelector('#play').addEventListener('click', async () => {
// Kontext erst nach einer Nutzeraktion anlegen (Autoplay-Richtlinie)
ctx ??= new AudioContext({ latencyHint: 'interactive' });
if (ctx.state === 'suspended') await ctx.resume();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.value = 440; // Kammerton A
// Kurzes Ein- und Ausblenden, damit es nicht knackt
const now = ctx.currentTime;
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(0.3, now + 0.02);
gain.gain.exponentialRampToValueAtTime(0.001, now + 1);
osc.connect(gain).connect(ctx.destination);
osc.start(now);
osc.stop(now + 1);
console.log(ctx.state, ctx.sampleRate);
});
Audiodatei laden, dekodieren und abspielen
const ctx = new AudioContext();
const loadSound = async (url) => {
const res = await fetch(url);
const data = await res.arrayBuffer();
return ctx.decodeAudioData(data); // Promise<AudioBuffer>
};
const playBuffer = (buffer, when = 0) => {
const src = ctx.createBufferSource();
src.buffer = buffer;
src.connect(ctx.destination);
src.start(ctx.currentTime + when);
return src;
};
document.querySelector('#shot').addEventListener('click', async () => {
await ctx.resume();
const buffer = await loadSound('/sounds/laser.mp3');
console.log(`Dauer: ${buffer.duration.toFixed(2)} s`);
playBuffer(buffer);
});
<audio>-Element analysieren (Pegelanzeige)
const audioEl = document.querySelector('audio');
const ctx = new AudioContext();
const source = ctx.createMediaElementSource(audioEl);
const analyser = ctx.createAnalyser();
analyser.fftSize = 256;
source.connect(analyser).connect(ctx.destination);
const data = new Uint8Array(analyser.frequencyBinCount);
const tick = () => {
analyser.getByteFrequencyData(data);
const avg = data.reduce((a, b) => a + b, 0) / data.length;
document.querySelector('#meter').style.width = `${avg / 2.55}%`;
requestAnimationFrame(tick);
};
audioEl.addEventListener('play', async () => {
await ctx.resume();
tick();
});
Kontext pausieren und freigeben
const ctx = new AudioContext();
ctx.addEventListener('statechange', () => {
console.log('Status:', ctx.state);
});
const pause = () => ctx.suspend(); // Uhr hält an, spart Rechenzeit
const weiter = () => ctx.resume();
const beenden = async () => {
await ctx.close(); // Ressourcen endgültig freigeben
console.log('Geschlossen:', ctx.state);
};
await weiter();
await pause();
await beenden();
// Wichtig · Fallstricke
- Autoplay-Richtlinie: Wird ein Kontext ohne Nutzerinteraktion erzeugt, startet er meist im Zustand
"suspended". Ruferesume()in einemclick- oderkeydown-Handler auf, sonst bleibt es still und es erscheint keine Fehlermeldung. - Ressourcen: Browser begrenzen die Zahl gleichzeitiger Kontexte. Lege keinen neuen Kontext pro Ton an. Verwende einen gemeinsamen Kontext und schließe ihn mit
close(). Nachclose()lässt er sich nicht wiederverwenden. - Einmal-Quellen:
AudioBufferSourceNodeundOscillatorNodekann man nur einmal starten. Für jede Wiedergabe brauchst du einen neuen Knoten. Das ist günstig, weil derAudioBufferwiederverwendet werden kann. - createMediaElementSource: Pro
<audio>/<video>-Element ist nur ein Aufruf erlaubt. Bei Medien von fremden Ursprüngen ohne passende CORS-Header (crossorigin-Attribut) liefert die Analyse nur Stille. - Kompatibilität: Ältere Safari-Versionen (vor 14.1) kennen nur
webkitAudioContext. Als Rückfall dientconst AC = window.AudioContext || window.webkitAudioContext;.sinkId/setSinkId()ist noch nicht überall verfügbar. - Knacken vermeiden: Setze Lautstärke nicht sprunghaft, sondern mit
setValueAtTime()und Rampen.exponentialRampToValueAtTime()darf den Zielwert0nicht verwenden.