Audio des Nutzers aufnehmen

Viele Browser können jetzt auf die Video- und Audioeingabe des Nutzers zugreifen. Je nach Browser kann es sich jedoch um eine vollständig dynamische und Inline-Ansicht handeln oder die Funktion wird an eine andere App auf dem Gerät des Nutzers delegiert.

Einfach anfangen und nach und nach steigern

Am einfachsten ist es, den Nutzer nach einer vorab aufgezeichneten Datei zu fragen. Erstellen Sie dazu ein einfaches Dateieingabeelement und fügen Sie einen accept-Filter hinzu, der angibt, dass nur Audiodateien akzeptiert werden dürfen, sowie ein capture-Attribut, das angibt, dass die Daten direkt vom Mikrofon abgerufen werden sollen.

<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. Dabei wird das Attribut capture ignoriert. In Safari auf iOS wird die Mikrofon-App geöffnet, mit der Sie Audio aufnehmen und dann an die Webseite zurücksenden können. Auf Android-Geräten kann der Nutzer auswählen, mit welcher App er die Audioaufnahme machen möchte, bevor er sie an die Webseite zurücksendet.

Sobald der Nutzer die Aufzeichnung beendet hat und wieder auf der Website ist, müssen Sie irgendwie an die Dateidaten gelangen. Sie können schnell darauf zugreifen, indem Sie dem Eingabeelement ein onchange-Ereignis zuordnen und dann die files-Eigenschaft des Ereignisobjekts lesen.

<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 damit alles tun, was Sie möchten. Beispielsweise können Sie…

  • Sie können sie direkt an ein <audio>-Element anhängen, damit sie abgespielt werden kann.
  • Sie laden sie auf das Gerät des Nutzers herunter.
  • Laden Sie es auf einen Server hoch, indem Sie es an einen XMLHttpRequest anhängen.
  • Sie geben sie an die Web Audio API weiter und wenden Filter darauf an.

Die Methode, über ein Eingabeelement auf Audiodaten zuzugreifen, ist zwar weit verbreitet, aber die am wenigsten empfehlenswerte Option. Wir möchten unbedingt Zugriff auf das Mikrofon erhalten und Nutzern direkt auf der Seite eine gute Nutzererfahrung bieten.

Interaktiven Zugriff auf das Mikrofon

Moderne Browser können eine direkte Verbindung zum Mikrofon haben, sodass wir Funktionen entwickeln können, die vollständig in die Webseite eingebunden sind und bei denen der Nutzer den Browser nie verlässt.

Zugriff auf das Mikrofon erhalten

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

Bei Erfolg gibt die API einen Stream zurück, der die Daten entweder von der Kamera oder vom Mikrofon enthält. Dieser kann dann einem <audio>-Element, einem WebRTC-Stream, einer Web Audio AudioContext oder mit der MediaRecorder API gespeichert werden.

Um Daten vom Mikrofon zu erhalten, legen wir einfach audio: true im Objekt „constraints“ 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 zuerst die verfügbaren Mikrofone auflisten.

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

Sie können dann die gewünschte deviceId übergeben, wenn Sie getUserMedia aufrufen.

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

Das ist an sich nicht sehr nützlich. Wir können nur die Audiodaten abspielen.

Zugriff auf die Rohdaten vom Mikrofon

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 an Knoten anschließt, die die Audiodaten verarbeiten können (z. B. Verstärkung anpassen) und schließlich an einen Lautsprecher, damit der Nutzer sie hören kann.

Einer der Knoten, die Sie verbinden können, ist ein AudioWorkletNode. Mit diesem Knoten haben Sie die Möglichkeit, benutzerdefinierte Audioverarbeitung auf niedriger Ebene durchzuführen. Die eigentliche Audioverarbeitung erfolgt in der process()-Callback-Methode in der AudioWorkletProcessor. Rufen Sie diese Funktion auf, um Eingaben und Parameter anzugeben 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 in den Puffern gespeicherten Daten sind die Rohdaten vom Mikrofon. Sie haben verschiedene Möglichkeiten, wie Sie diese Daten verwenden können:

  • Direkt auf den Server hochladen
  • Lokal speichern
  • Konvertieren Sie sie in ein spezielles Dateiformat wie WAV und speichern Sie sie dann auf Ihren Servern oder lokal.

Daten vom Mikrofon speichern

Die Daten vom Mikrofon lassen sich am einfachsten mit der MediaRecorder API speichern.

Die MediaRecorder API nimmt den von getUserMedia erstellten Stream auf und speichert die Daten im Stream nach und nach an Ihrem gewünschten 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 eine Blob umwandeln können. Diese kann dann verwendet werden, um die Daten auf unserem Webserver oder direkt im Speicher des Geräts des Nutzers zu speichern.

Um Erlaubnis zur verantwortungsvollen Verwendung des Mikrofons bitten

Wenn der Nutzer Ihrer Website noch keinen Zugriff auf das Mikrofon gewährt hat, wird er vom Browser aufgefordert, dies zu tun, sobald Sie getUserMedia aufrufen.

Nutzer mögen es nicht, wenn sie zum Zugriff auf leistungsstarke Geräte auf ihrem Computer aufgefordert werden. Sie blockieren die Anfrage häufig oder ignorieren sie, wenn sie den Kontext der Aufforderung nicht verstehen. Es wird empfohlen, nur dann um Zugriff auf das Mikrofon zu bitten, wenn es zum ersten Mal benötigt wird. Sobald der Nutzer den Zugriff gewährt hat, wird er nicht noch einmal gefragt. Wenn er den Zugriff jedoch ablehnt, können Sie ihn nicht noch einmal um Erlaubnis bitten.

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

Die getUserMedia API gibt Ihnen keine Auskunft darüber, ob Sie bereits Zugriff auf das Mikrofon haben. Das stellt Sie vor ein Problem: Wenn Sie eine ansprechende Benutzeroberfläche erstellen möchten, um Nutzer dazu zu bringen, Ihnen Zugriff auf das Mikrofon zu gewähren, müssen Sie um Zugriff auf das Mikrofon bitten.

In einigen Browsern kann das Problem mithilfe der Permission API behoben werden. Mit der navigator.permission API kannst du den Status der Zugriffsberechtigung für bestimmte APIs abfragen, ohne dass du noch einmal aufgefordert wirst.

Wenn Sie prüfen möchten, ob Sie Zugriff auf das Mikrofon des Nutzers haben, können Sie {name: 'microphone'} in die Abfragemethode übergeben. Es wird dann Folgendes zurückgegeben:

  • granted: Der Nutzer hat Ihnen zuvor Zugriff auf das Mikrofon gewährt.
  • prompt: Der Nutzer hat dir keinen Zugriff gewährt und wird aufgefordert, wenn du getUserMedia aufrufst.
  • denied: Der Zugriff auf das Mikrofon wurde vom System oder vom Nutzer explizit blockiert und Sie können nicht darauf zugreifen.

Außerdem können Sie jetzt schnell prüfen, ob Sie Ihre Benutzeroberfläche an die Aktionen anpassen müssen, die der Nutzer ausführen muss.

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