Cara memproses audio dari mikrofon pengguna

François Beaufort
François Beaufort

Kamera dan mikrofon pengguna dapat diakses di platform web dengan Media Capture and Streams API. Metode getUserMedia() meminta pengguna mengakses kamera dan/atau mikrofon untuk merekam sebagai streaming media. Streaming ini kemudian dapat diproses dalam thread Audio Web terpisah dengan AudioWorklet yang menyediakan pemrosesan audio latensi sangat rendah.

Contoh di bawah ini menunjukkan cara memproses audio dari mikrofon pengguna dengan cara yang efektif.

let stream;

startMicrophoneButton.addEventListener("click", async () => {
  // Prompt the user to use their microphone.
  stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
  });
  const context = new AudioContext();
  const source = context.createMediaStreamSource(stream);

  // Load and execute the module script.
  await context.audioWorklet.addModule("processor.js");
  // Create an AudioWorkletNode. The name of the processor is the
  // one passed to registerProcessor() in the module script.
  const processor = new AudioWorkletNode(context, "processor");

  source.connect(processor).connect(context.destination);
  log("Your microphone audio is being used.");
});

stopMicrophoneButton.addEventListener("click", () => {
  // Stop the stream.
  stream.getTracks().forEach(track => track.stop());

  log("Your microphone audio is not used anymore.");
});
// processor.js
// This file is evaluated in the audio rendering thread
// upon context.audioWorklet.addModule() call.

class Processor extends AudioWorkletProcessor {
  process([input], [output]) {
    // Copy inputs to outputs.
    output[0].set(input[0]);
    return true;
  }
}

registerProcessor("processor", Processor);

Dukungan browser

MediaDevices.getUserMedia()

Dukungan Browser

  • 53
  • 12
  • 36
  • 11

Sumber

Audio Web

Dukungan Browser

  • 35
  • 12
  • 25
  • 14.1

Sumber

AudioWorklet

Dukungan Browser

  • 66
  • 79
  • 76
  • 14.1

Sumber

Bacaan lebih lanjut

Demo

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎙️</text></svg>"
    />
    <title>How to process audio from the user's microphone</title>
  </head>
  <body>
    <h1>How to process audio from the user's microphone</h1>
    <button id="startMicrophoneButton">Start using microphone</button>
    <button id="stopMicrophoneButton" disabled>Stop using microphone</button>
    <pre id="logs"></pre>
  </body>
</html>

CSS


        :root {
  color-scheme: dark light;
}
html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
body {
  margin: 1rem;
  font-family: system-ui, sans-serif;
}
button {
  display: block;
  margin-bottom: 4px;
}
pre {
  color: red;
  white-space: pre-line;
}
        

JS


        const startMicrophoneButton = document.querySelector('#startMicrophoneButton');
const stopMicrophoneButton = document.querySelector('#stopMicrophoneButton');

let stream;

startMicrophoneButton.addEventListener("click", async () => {
  // Prompt the user to use their microphone.
  stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
  });
  const context = new AudioContext();
  const source = context.createMediaStreamSource(stream);

  // Load and execute the module script.
  await context.audioWorklet.addModule("processor.js");
  // Create an AudioWorkletNode. The name of the processor is the
  // one passed to registerProcessor() in the module script.
  const processor = new AudioWorkletNode(context, "processor");

  source.connect(processor).connect(context.destination);

  stopMicrophoneButton.disabled = false;
  log("Your microphone audio is being used.");
});

stopMicrophoneButton.addEventListener("click", () => {
  // Stop the stream.
  stream.getTracks().forEach(track => track.stop());

  log("Your microphone audio is not used anymore.");
});