Signatur
Beschreibung
MediaStreamAudioSourceNode verbindet Live-Audio aus einem MediaStream mit der Web Audio API. Typische Quellen sind das Mikrofon über navigator.mediaDevices.getUserMedia(), eine Bildschirmfreigabe über getDisplayMedia() oder ein entfernter Teilnehmer einer WebRTC-Verbindung (RTCPeerConnection). Der Knoten hat keine Eingänge und genau einen Ausgang. Die Kanalanzahl des Ausgangs richtet sich nach der Audiospur.
Erzeugt wird der Knoten entweder über die Fabrikmethode AudioContext.prototype.createMediaStreamSource(stream) oder den Konstruktor new MediaStreamAudioSourceNode(context, { mediaStream }). Danach lässt er sich mit anderen Knoten verbinden, z. B. mit einem AnalyserNode für Pegelanzeigen und Visualisierungen, einem GainNode für die Lautstärke, Filtern für Effekte oder einem MediaStreamAudioDestinationNode, um das bearbeitete Audio wieder als Stream auszugeben (etwa für MediaRecorder oder WebRTC).
Der Knoten übernimmt nur die erste Audiospur des Streams. Welche das ist, bestimmt der Browser durch lexikografische Sortierung der Spur-IDs, nicht die Reihenfolge der Spuren im Stream. Brauchst du eine bestimmte Spur, nimm MediaStreamTrackAudioSourceNode bzw. createMediaStreamTrackSource().
Die einzige eigene Eigenschaft ist mediaStream (nur lesbar). Sie liefert den MediaStream, der beim Erzeugen übergeben wurde. Alle weiteren Eigenschaften und Methoden (connect(), disconnect(), channelCount …) erbt der Knoten von AudioNode.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $context Pflicht | AudioContext | Der AudioContext, zu dem der Knoten gehört (Konstruktor-Parameter). Ein OfflineAudioContext ist nicht erlaubt. |
|
| $options Pflicht | { mediaStream: MediaStream } | Optionsobjekt mit der Pflicht-Eigenschaft mediaStream: der Stream, dessen erste Audiospur als Quelle dient. |
Rückgabewert
mediaStream verweist auf den übergebenen Stream.Beispiele
Mikrofon abhören und Lautstärke regeln
const startMic = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const ctx = new AudioContext();
// Fabrikmethode – gleichwertig zum Konstruktor
const source = ctx.createMediaStreamSource(stream);
const gain = ctx.createGain();
gain.gain.value = 0.5;
source.connect(gain).connect(ctx.destination);
console.log(source.mediaStream === stream);
return { ctx, stream };
};
document.querySelector('#start').addEventListener('click', startMic);
Pegelanzeige mit AnalyserNode (Konstruktor-Variante)
const showLevel = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const ctx = new AudioContext();
const source = new MediaStreamAudioSourceNode(ctx, { mediaStream: stream });
const analyser = new AnalyserNode(ctx, { fftSize: 256 });
source.connect(analyser); // nicht mit destination verbinden -> keine Rückkopplung
const data = new Uint8Array(analyser.fftSize);
const tick = () => {
analyser.getByteTimeDomainData(data);
const peak = Math.max(...data.map((v) => Math.abs(v - 128))) / 128;
document.querySelector('#meter').value = peak;
requestAnimationFrame(tick);
};
tick();
};
document.querySelector('#meter-start').addEventListener('click', showLevel);
WebRTC-Gegenstelle filtern und aufnehmen
const pc = new RTCPeerConnection();
const ctx = new AudioContext();
pc.addEventListener('track', ({ streams: [remoteStream] }) => {
const source = ctx.createMediaStreamSource(remoteStream);
const highpass = new BiquadFilterNode(ctx, { type: 'highpass', frequency: 120 });
const dest = ctx.createMediaStreamDestination();
source.connect(highpass).connect(dest);
const recorder = new MediaRecorder(dest.stream);
recorder.addEventListener('dataavailable', (e) => console.log('Chunk:', e.data.size, 'Bytes'));
recorder.start(1000);
});
Aufräumen: Stream und Kontext beenden
const stopMic = async ({ ctx, stream }) => {
stream.getTracks().forEach((track) => track.stop()); // Mikrofon-Anzeige erlischt
await ctx.close();
console.log(ctx.state);
};
// Wichtig · Fallstricke
- Autoplay-Richtlinie: Ein
AudioContext, der ohne Nutzerinteraktion entsteht, startet oft im Zustandsuspended. Erzeuge ihn in einem Klick-Handler oder rufectx.resume()auf. - Keine Audiospur: Enthält der Stream keine Audiospur, werfen der Konstruktor und
createMediaStreamSource()einenInvalidStateError. - Nur erste Spur: Bei mehreren Audiospuren wird nur eine verwendet, sortiert nach ID. Für eine gezielte Auswahl nimm
MediaStreamTrackAudioSourceNode. Firefox unterstützt diesen Knoten; bei Chromium und Safari ist die Unterstützung eingeschränkt, deshalb vorher prüfen. - Rückkopplung: Wird ein Mikrofon direkt mit
ctx.destinationverbunden, kann es über Lautsprecher pfeifen. Nutze Kopfhörer oder verbinde nur mit einem Analyser. - Sicherheit/Datenschutz:
getUserMedia()funktioniert nur in sicheren Kontexten (HTTPS oder localhost) und braucht die Zustimmung der Nutzer. Beende die Spuren mittrack.stop(), wenn du sie nicht mehr brauchst. - Cross-Origin: Stammt der Stream aus Medien einer anderen Herkunft ohne CORS-Freigabe, liefert der Knoten nur Stille.
- Abtastrate: Firefox hat früher einen Fehler geworfen, wenn die Abtastrate von Kontext und Mikrofon nicht übereinstimmte. Lässt man die Abtastrate beim
AudioContextweg, vermeidet man das Problem. OfflineAudioContextwird nicht unterstützt.