Merekam Audio dari Pengguna

Banyak browser kini memiliki kemampuan untuk mengakses input video dan audio dari pengguna. Namun, bergantung pada browser, pengalaman ini mungkin berupa pengalaman inline dan dinamis penuh, atau dapat didelegasikan ke aplikasi lain di perangkat pengguna.

Mulai dengan sederhana dan bertahap

Cara termudah untuk melakukannya adalah dengan meminta file yang telah direkam sebelumnya kepada pengguna. Lakukan ini dengan membuat elemen input file sederhana dan menambahkan filter accept yang menunjukkan bahwa kita hanya dapat menerima file audio, dan atribut capture yang menunjukkan bahwa kita ingin mendapatkannya langsung dari mikrofon.

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

Metode ini berfungsi di semua platform. Di desktop, pengguna akan diminta untuk mengupload file dari sistem file (mengabaikan atribut capture). Di Safari di iOS, tindakan ini akan membuka aplikasi mikrofon, yang memungkinkan Anda merekam audio, lalu mengirimnya kembali ke halaman web. Di Android, tindakan ini akan memberi pengguna pilihan aplikasi yang akan digunakan untuk merekam audio sebelum mengirimnya kembali ke halaman web.

Setelah pengguna selesai merekam dan kembali ke situs, Anda harus mendapatkan data file. Anda bisa mendapatkan akses cepat dengan melampirkan peristiwa onchange ke elemen input, lalu membaca properti files objek peristiwa.

<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>

Setelah memiliki akses ke file, Anda dapat melakukan apa pun yang Anda inginkan dengan file tersebut. Misalnya, Anda dapat:

  • Lampirkan langsung ke elemen <audio> agar Anda dapat memutarnya
  • Mendownloadnya ke perangkat pengguna
  • Upload ke server dengan melampirkan ke XMLHttpRequest
  • Teruskan melalui Web Audio API dan terapkan filter ke dalamnya

Meskipun metode elemen input untuk mendapatkan akses ke data audio sangat umum, ini adalah opsi yang paling tidak menarik. Kami sangat ingin mendapatkan akses ke mikrofon dan memberikan pengalaman yang baik langsung di halaman.

Mengakses mikrofon secara interaktif

Browser modern dapat memiliki saluran langsung ke mikrofon yang memungkinkan kita membuat pengalaman yang terintegrasi sepenuhnya dengan halaman web dan pengguna tidak akan pernah keluar dari browser.

Mendapatkan akses ke mikrofon

Kita dapat langsung mengakses Mikrofon menggunakan API dalam spesifikasi WebRTC yang disebut getUserMedia(). getUserMedia() akan meminta akses ke mikrofon dan kamera yang terhubung.

Jika berhasil, API akan menampilkan Stream yang akan berisi data dari kamera atau mikrofon, lalu kita dapat melampirkan Stream ke elemen <audio>, melampirkan Stream ke streaming WebRTC, melampirkan Stream ke AudioContext Audio Web, atau menyimpannya menggunakan MediaRecorder API.

Untuk mendapatkan data dari mikrofon, kita cukup menetapkan audio: true dalam objek batasan yang diteruskan ke getUserMedia() API.

<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>

Jika ingin memilih mikrofon tertentu, Anda dapat menghitung mikrofon yang tersedia terlebih dahulu.

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

Kemudian, Anda dapat meneruskan deviceId yang ingin digunakan saat memanggil getUserMedia.

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

Hal ini tidak terlalu berguna. Yang dapat kita lakukan hanyalah mengambil data audio dan memutarnya.

Mengakses data mentah dari mikrofon

Untuk mengakses data mentah dari mikrofon, kita harus mengambil streaming yang dibuat oleh getUserMedia(), lalu menggunakan Web Audio API untuk memproses data. Web Audio API adalah API sederhana yang mengambil sumber input dan menghubungkan sumber tersebut ke node yang dapat memproses data audio (menyesuaikan Gain, dll.) dan pada akhirnya ke speaker sehingga pengguna dapat mendengarnya.

Salah satu node yang dapat Anda hubungkan adalah AudioWorkletNode. Node ini memberi Anda kemampuan tingkat rendah untuk pemrosesan audio kustom. Pemrosesan audio yang sebenarnya terjadi di metode callback process() di AudioWorkletProcessor. Panggil fungsi ini untuk memasukkan input dan parameter serta mengambil output.

Lihat Enter Audio Worklet untuk mempelajari lebih lanjut.

<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);

Data yang disimpan dalam buffering adalah data mentah dari mikrofon dan Anda memiliki sejumlah opsi terkait tindakan yang dapat Anda lakukan dengan data tersebut:

  • Menguploadnya langsung ke server
  • Menyimpan secara lokal
  • Konversikan ke format file khusus, seperti WAV, lalu simpan ke server atau secara lokal

Menyimpan data dari mikrofon

Cara termudah untuk menyimpan data dari mikrofon adalah dengan menggunakan MediaRecorder API.

MediaRecorder API akan mengambil streaming yang dibuat oleh getUserMedia, lalu secara bertahap menyimpan data yang ada di streaming ke tujuan yang Anda inginkan.

<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>

Dalam kasus ini, kita menyimpan data langsung ke array yang nantinya dapat kita ubah menjadi Blob, yang kemudian dapat digunakan untuk menyimpan data ke Server Web atau langsung ke penyimpanan di perangkat pengguna.

Meminta izin untuk menggunakan mikrofon secara bertanggung jawab

Jika pengguna belum pernah memberikan akses ke mikrofon ke situs Anda, maka saat Anda memanggil getUserMedia, browser akan meminta pengguna untuk memberikan izin ke mikrofon ke situs Anda.

Pengguna tidak suka dimintai akses ke perangkat canggih di komputer mereka dan mereka akan sering memblokir permintaan tersebut, atau mereka akan mengabaikannya jika tidak memahami konteks pembuatan perintah. Praktik terbaiknya adalah hanya meminta akses ke mikrofon saat pertama kali diperlukan. Setelah pengguna memberikan akses, mereka tidak akan diminta lagi. Namun, jika mereka menolak akses, Anda tidak dapat meminta izin lagi kepada pengguna.

Menggunakan API izin untuk memeriksa apakah Anda sudah memiliki akses

getUserMedia API tidak memberi Anda informasi apakah Anda sudah memiliki akses ke mikrofon. Hal ini menimbulkan masalah, untuk memberikan UI yang bagus agar pengguna memberikan akses ke mikrofon, Anda harus meminta akses ke mikrofon.

Hal ini dapat diatasi di beberapa browser menggunakan Permission API. navigator.permission API memungkinkan Anda membuat kueri status kemampuan untuk mengakses API tertentu tanpa harus meminta lagi.

Untuk membuat kueri apakah Anda memiliki akses ke mikrofon pengguna, Anda dapat meneruskan {name: 'microphone'} ke metode kueri dan metode tersebut akan menampilkan:

  • granted — pengguna sebelumnya telah memberi Anda akses ke mikrofon;
  • prompt — pengguna belum memberi Anda akses dan akan diminta saat Anda memanggil getUserMedia;
  • denied — sistem atau pengguna telah memblokir akses ke mikrofon secara eksplisit dan Anda tidak akan dapat mengaksesnya.

Dan sekarang Anda dapat dengan cepat memeriksa apakah perlu mengubah antarmuka pengguna untuk mengakomodasi tindakan yang perlu dilakukan pengguna.

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 () {};
});

Masukan