Audio vom Nutzer aufnehmen

Viele Browser können jetzt auf Video- und Audioeingaben des Nutzers zugreifen. Je nach Browser kann es sich jedoch um eine vollständig dynamische und Inline-Erfahrung handeln oder die Wiedergabe kann 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, sowie ein capture-Attribut, das angibt, dass die Audiodatei direkt vom Mikrofon stammen soll.

<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 unter iOS wird die Mikrofon-App geöffnet, mit der Sie Audio aufnehmen und dann an die Webseite zurücksenden können. Unter Android kann der Nutzer auswählen, mit welcher App er Audio aufnehmen möchte, bevor es an die Webseite zurückgesendet wird.

Sobald der Nutzer die Aufnahme beendet hat und wieder auf der Website ist, müssen Sie die Dateidaten irgendwie abrufen. Sie können schnell darauf zugreifen, indem Sie ein onchange-Ereignis an das Eingabeelement anhängen und dann das files-Attribut 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 machen, was Sie wollen. Beispielsweise können Sie…

  • Hängen Sie es direkt an ein <audio>-Element an, damit Sie es abspielen können.
  • Laden Sie die App auf das Gerät des Nutzers herunter.
  • Laden Sie sie auf einen Server hoch, indem Sie sie an eine XMLHttpRequest anhängen.
  • Über die Web Audio API leiten und Filter darauf anwenden

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

Interaktiv auf das Mikrofon zugreifen

Moderne Browser können eine direkte Verbindung zum Mikrofon herstellen. So können wir Funktionen entwickeln, die vollständig in die Webseite integriert sind, und der Nutzer muss den Browser nie verlassen.

Zugriff auf das Mikrofon erhalten

Wir können direkt auf das Mikrofon zugreifen, indem wir eine API in der WebRTC-Spezifikation namens getUserMedia() verwenden. getUserMedia() fordert den Nutzer auf, den Zugriff auf seine verbundenen Mikrofone und Kameras zu gewähren.

Bei Erfolg gibt die API ein Stream-Objekt zurück, das die Daten der Kamera oder des Mikrofons enthält. Diese können dann an ein <audio>-Element, einen WebRTC-Stream oder einen Web Audio-AudioContext angehängt oder mit der MediaRecorder API gespeichert werden.

Um Daten vom Mikrofon zu erhalten, legen wir 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 zuerst 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 Sie beim Aufrufen von getUserMedia verwenden möchten.

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

Für sich genommen ist das nicht besonders nützlich. Wir können die Audiodaten nur abspielen.

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 können (z. B. die Verstärkung anpassen) und schließlich mit einem Lautsprecher, damit der Nutzer sie hören kann.

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

Weitere Informationen finden Sie unter 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 Zwischenspeichern enthaltenen Daten sind die Rohdaten des Mikrofons. Du hast mehrere Möglichkeiten, was du mit diesen Daten tun kannst:

  • Direkt auf den Server hochladen
  • Lokal speichern
  • Konvertieren Sie sie 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 nach und nach am 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 ein Blob-Objekt umwandeln können. Dieses kann dann verwendet werden, um die Daten auf unserem Webserver oder direkt im Speicher des Nutzergeräts zu speichern.

Berechtigung zur verantwortungsvollen Verwendung des Mikrofons einholen

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

Nutzer hassen es, wenn sie aufgefordert werden, Zugriff auf leistungsstarke Geräte auf ihrem Computer zu gewähren. Sie blockieren die Anfrage häufig oder ignorieren sie, wenn sie den Kontext der Aufforderung nicht verstehen. Es empfiehlt sich, erst dann nach dem Zugriff auf das Mikrofon zu fragen, wenn er 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 Permissions API prüfen, ob Sie bereits Zugriff haben

Die getUserMedia API gibt keine Auskunft darüber, ob Sie bereits Zugriff auf das Mikrofon haben. Das stellt Sie vor ein Problem: Um eine ansprechende Benutzeroberfläche bereitzustellen, über die der Nutzer Ihnen Zugriff auf das Mikrofon gewährt, müssen Sie Zugriff auf das Mikrofon anfordern.

In einigen Browsern kann dieses Problem mithilfe der Permission API gelöst werden. Mit der navigator.permission API kannst du den Status der Zugriffsmöglichkeit auf bestimmte APIs abfragen, ohne noch einmal nachfragen zu müssen.

Wenn du prüfen möchtest, ob du Zugriff auf das Mikrofon des Nutzers hast, kannst du {name: 'microphone'} an die Abfragemethode übergeben. Es wird dann einer der folgenden Werte 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, dies zu tun, wenn du getUserMedia aufrufst.
  • denied: Das System oder der Nutzer hat den Zugriff auf das Mikrofon explizit blockiert und Sie können nicht darauf zugreifen.

Sie können jetzt schnell prüfen, ob Sie die Benutzeroberfläche anpassen müssen, um die Aktionen zu ermöglichen, 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