Audio des Nutzers aufnehmen

Viele Browser haben jetzt die Möglichkeit, auf Video- und Audioeingaben des Nutzers zuzugreifen. Je nach Browser kann dies jedoch vollständig dynamisch und inline sein oder an eine andere App auf dem Gerät des Nutzers delegiert werden.

Einfach und schrittweise beginnen

Am einfachsten ist es, den Nutzer um eine vorab aufgezeichnete Datei zu bitten. Erstellen Sie dazu ein einfaches Dateieingabeelement und fügen Sie einen accept-Filter hinzu, der angibt, dass nur Audiodateien akzeptiert werden können, sowie ein capture-Attribut, das angibt, dass wir es direkt vom Mikrofon abrufen möchten.

<input type="file" accept="audio/*" capture />

Diese Methode funktioniert auf allen Plattformen. Auf dem Computer wird der Nutzer aufgefordert, eine Datei aus dem Dateisystem hochzuladen. Das Attribut capture wird dabei ignoriert. In Safari wird unter iOS die Mikrofon-App geöffnet, über die Sie Audio aufzeichnen und dann zurück an die Webseite senden können. Auf Android-Geräten kann der Nutzer auswählen, in welcher App das Audio aufgenommen werden soll, bevor es zurück zur Webseite geleitet wird.

Sobald der Nutzer die Aufzeichnung abgeschlossen hat und wieder auf der Website ist, müssen Sie irgendwie auf die Dateidaten zugreifen. Zum schnellen Zugriff hängen Sie ein onchange-Ereignis an das Eingabeelement an und lesen dann die files-Eigenschaft des Ereignisobjekts.

<input type="file" accept="audio/*" capture id="recorder" />
<audio id="player" controls></audio>
  <script>
    const recorder = document.getElementById('recorder');
    const player = document.getElementById('player');

    recorder.addEventListener('change', function (e) {
      const file = e.target.files[0];
      const url = URL.createObjectURL(file);
      // Do something with the audio file.
      player.src = url;
    });
  </script>
</audio>

Sobald Sie Zugriff auf die Datei haben, können Sie mit ihr alles tun, was Sie möchten. Beispielsweise können Sie…

  • Hängen Sie es direkt an ein <audio>-Element an, um es abspielen zu können
  • Auf das Gerät des Nutzers herunterladen
  • Laden Sie sie auf einen Server hoch, indem Sie sie an eine XMLHttpRequest anhängen
  • Sie muss die Web Audio API durchlaufen und Filter darauf anwenden.

Die Eingabemethode für den Zugriff auf Audiodaten ist zwar überall, aber die am wenigsten attraktivste Option. Wir möchten Zugriff auf das Mikrofon und eine positive Erfahrung direkt auf der Seite.

Interaktiver Zugriff auf das Mikrofon

Moderne Browser können eine direkte Verbindung zum Mikrofon haben. Dies ermöglicht es uns, Erlebnisse zu schaffen, die vollständig in die Webseite integriert sind, sodass der Nutzer den Browser niemals verlässt.

Zugriff auf das Mikrofon erhalten

Wir können über eine API in der WebRTC-Spezifikation namens getUserMedia() direkt auf das Mikrofon zugreifen. getUserMedia() fordert den Nutzer auf, Zugriff auf die verbundenen Mikrofone und Kameras zu erhalten.

Bei Erfolg gibt die API ein Stream zurück, das die Daten der Kamera oder des Mikrofons enthält. Wir können es dann entweder an ein <audio>-Element anhängen, an einen WebRTC-Stream anhängen oder an eine Web Audio-AudioContext anhängen oder es über die MediaRecorder API speichern.

Um Daten vom Mikrofon abzurufen, legen Sie einfach audio: true im Einschränkungsobjekt fest, das an die getUserMedia() API übergeben wird.

<audio id="player" controls></audio>
<script>
  const player = document.getElementById('player');

  const handleSuccess = function (stream) {
    if (window.URL) {
      player.srcObject = stream;
    } else {
      player.src = stream;
    }
  };

  navigator.mediaDevices
    .getUserMedia({audio: true, video: false})
    .then(handleSuccess);
</script>

Wenn Sie ein bestimmtes Mikrofon auswählen möchten, können Sie zunächst die verfügbaren Mikrofone auflisten.

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices = devices.filter((d) => d.kind === 'audioinput');
});

Sie können dann die deviceId übergeben, die beim Aufruf von getUserMedia verwendet werden soll.

navigator.mediaDevices.getUserMedia({
  audio: {
    deviceId: devices[0].deviceId,
  },
});

Alleine ist das nicht besonders nützlich. Wir nehmen die Audiodaten und spielen sie ab.

Auf die Rohdaten des Mikrofons zugreifen

Um auf die Rohdaten des Mikrofons zuzugreifen, müssen wir den von getUserMedia() erstellten Stream verwenden und die Daten dann mit der Web Audio API verarbeiten. Die Web Audio API ist eine einfache API, die Eingabequellen verwendet und diese Quellen mit Knoten verbindet, die die Audiodaten verarbeiten (Verstärkung usw. anpassen) und schließlich mit einem Lautsprecher verbinden können, damit der Nutzer sie hören kann.

Einer der Knoten, den Sie verbinden können, ist ein AudioWorkletNode. Dieser Knoten bietet Ihnen die Low-Level-Funktion zur benutzerdefinierten Audioverarbeitung. Die eigentliche Audioverarbeitung erfolgt in der Callback-Methode process() im AudioWorkletProcessor. Rufen Sie diese Funktion auf, um Eingaben und Parameter zu füttern und Ausgaben abzurufen.

Weitere Informationen finden Sie unter Enter Audio Worklet.

<script>
  const handleSuccess = async function(stream) {
    const context = new AudioContext();
    const source = context.createMediaStreamSource(stream);

    await context.audioWorklet.addModule("processor.js");
    const worklet = new AudioWorkletNode(context, "worklet-processor");

    source.connect(worklet);
    worklet.connect(context.destination);
  };

  navigator.mediaDevices.getUserMedia({ audio: true, video: false })
      .then(handleSuccess);
</script>
// processor.js
class WorkletProcessor extends AudioWorkletProcessor {
  process(inputs, outputs, parameters) {
    // Do something with the data, e.g. convert it to WAV
    console.log(inputs);
    return true;
  }
}

registerProcessor("worklet-processor", WorkletProcessor);

Die Daten in den Puffern sind die Rohdaten aus dem Mikrofon. Sie haben eine Reihe von Möglichkeiten, wie Sie diese Daten nutzen können:

  • Sie laden die Datei direkt auf den Server hoch.
  • Daten lokal speichern
  • Konvertieren Sie die Datei in ein dediziertes Dateiformat wie WAV und speichern Sie sie dann auf Ihren Servern oder lokal.

Daten vom Mikrofon speichern

Am einfachsten lassen sich die Daten vom Mikrofon mit der MediaRecorder API speichern.

Die MediaRecorder API nimmt den von getUserMedia erstellten Stream und speichert die Daten im Stream dann schrittweise an Ihrem bevorzugten Ziel.

<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
  const downloadLink = document.getElementById('download');
  const stopButton = document.getElementById('stop');


  const handleSuccess = function(stream) {
    const options = {mimeType: 'audio/webm'};
    const recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);

    mediaRecorder.addEventListener('dataavailable', function(e) {
      if (e.data.size > 0) recordedChunks.push(e.data);
    });

    mediaRecorder.addEventListener('stop', function() {
      downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
      downloadLink.download = 'acetest.wav';
    });

    stopButton.addEventListener('click', function() {
      mediaRecorder.stop();
    });

    mediaRecorder.start();
  };

  navigator.mediaDevices.getUserMedia({ audio: true, video: false })
      .then(handleSuccess);
</script>

In unserem Fall speichern wir die Daten direkt in einem Array, das wir später in ein Blob umwandeln können, das dann verwendet werden kann, um die Daten auf unserem Webserver oder direkt im Speicher auf dem Gerät des Nutzers zu speichern.

Berechtigung zur verantwortungsvollen Nutzung des Mikrofons einholen

Wenn der Nutzer Ihrer Website zuvor noch keinen Zugriff auf das Mikrofon gewährt hat, wird der Nutzer beim Aufruf von getUserMedia vom Browser aufgefordert, Ihrer Website die Berechtigung für das Mikrofon zu gewähren.

Nutzer mögen es ungern, wenn sie auf ihrem Computer zum Zugriff auf leistungsstarke Geräte aufgefordert werden. Sie blockieren die Anfrage häufig oder ignorieren sie, wenn sie den Kontext, für den die Aufforderung erstellt wurde, nicht verstehen. Es hat sich bewährt, den Zugriff auf das Mikrofon nur bei Bedarf anzufordern. Sobald der Nutzer den Zugriff gewährt hat, wird er nicht noch einmal gefragt. Wenn er den Zugriff jedoch ablehnt, können Sie den Nutzer nicht noch einmal um die Berechtigung bitten.

Mit der Permissions API prüfen, ob Sie bereits Zugriff haben

Die getUserMedia API teilt Ihnen nicht mit, ob Sie bereits Zugriff auf das Mikrofon haben. Dies stellt ein Problem dar. Um eine übersichtliche Benutzeroberfläche bereitzustellen, über die der Nutzer dir Zugriff auf das Mikrofon gewähren kann, musst du Zugriff auf das Mikrofon anfordern.

Dieses Problem lässt sich in einigen Browsern mithilfe der Permission API beheben. Mit der navigator.permission API können Sie den Status der Möglichkeit für den Zugriff auf bestimmte APIs abfragen, ohne noch einmal nachfragen zu müssen.

Um herauszufinden, ob Sie Zugriff auf das Mikrofon des Nutzers haben, können Sie {name: 'microphone'} an die Abfragemethode übergeben. Sie gibt dann eines der folgenden Ergebnisse zurück:

  • granted: Der Nutzer hat dir zuvor Zugriff auf das Mikrofon gewährt.
  • prompt: Der Nutzer hat Ihnen keinen Zugriff gewährt und wird gefragt, wenn Sie getUserMedia aufrufen.
  • denied: Das System oder der Nutzer hat den Zugriff auf das Mikrofon explizit blockiert und Sie können nicht darauf zugreifen.

Und Sie können jetzt schnell prüfen, ob Sie Ihre Benutzeroberfläche anpassen müssen, um den Aktionen des Nutzers Rechnung zu tragen.

navigator.permissions.query({name: 'microphone'}).then(function (result) {
  if (result.state == 'granted') {
  } else if (result.state == 'prompt') {
  } else if (result.state == 'denied') {
  }
  result.onchange = function () {};
});

Feedback