Merekam audio dan video dalam HTML5

Pengantar

Perekaman Audio/Video telah menjadi "Holy Grail" pengembangan web dalam waktu yang lama. Selama bertahun-tahun, kami harus mengandalkan plugin browser (Flash atau Silverlight) untuk menyelesaikan tugas itu. Ayo!

HTML5 dapat membantu. Ini mungkin tidak terlihat, tetapi kemunculan HTML5 telah membawa lonjakan akses ke perangkat keras perangkat. Geolokasi (GPS), Orientation API (akselerometer), WebGL (GPU), dan Web Audio API (hardware audio) adalah contoh yang sempurna. Fitur-fitur ini luar biasa canggih, mengekspos API JavaScript tingkat tinggi yang ada di atas kemampuan hardware yang mendasarinya pada sistem.

Tutorial ini memperkenalkan API baru, GetUserMedia, yang memungkinkan aplikasi web mengakses kamera dan mikrofon pengguna.

Jalan menuju getUserMedia()

Jika Anda tidak mengetahui sejarahnya, cara kita mencapai getUserMedia() API adalah kisah yang menarik.

Beberapa varian "Media Capture API" telah berkembang selama beberapa tahun terakhir. Banyak orang menyadari perlunya mengakses perangkat native di web, tetapi hal itu membuat semua orang dan ibu mereka membuat spesifikasi baru. Semuanya menjadi sangat berantakan sehingga W3C akhirnya memutuskan untuk membentuk kelompok kerja. Satu-satunya tujuan mereka? Jelaskan kegilaannya! Grup Kerja Kebijakan Perangkat API (DAP) telah ditugaskan untuk menggabungkan dan menstandarkan banyak proposal.

Aku akan mencoba merangkum apa yang terjadi pada tahun 2011...

Tahap 1: Pengambilan Media HTML

HTML Media Capture merupakan upaya pertama DAP dalam standarisasi pengambilan media di web. Cara ini bekerja dengan membebani <input type="file"> dan menambahkan nilai baru untuk parameter accept.

Jika ingin mengizinkan pengguna mengambil snapshot mereka dengan webcam, Anda dapat melakukannya dengan capture=camera:

<input type="file" accept="image/*;capture=camera">

Cara merekam video atau audio memiliki cara yang mirip:

<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">

Kelihatan bagus kan? Saya sangat suka bahwa ini menggunakan kembali input file. Secara semantik, itu masuk akal. Di mana "API" khusus ini gagal adalah kemampuan untuk melakukan efek realtime (misalnya merender data webcam langsung ke <canvas> dan menerapkan filter WebGL). Pengambilan Media HTML hanya memungkinkan Anda merekam file media atau mengambil snapshot tepat waktu.

Dukungan:

  • Browser Android 3.0 - salah satu implementasi pertama. Tonton video ini untuk melihat cara kerjanya.
  • Chrome untuk Android (0.16)
  • Firefox Mobile 10.0
  • iOS6 Safari dan Chrome (dukungan sebagian)

Putaran 2: elemen perangkat

Banyak yang beranggapan bahwa HTML Media Capture terlalu membatasi, sehingga muncul spesifikasi baru yang mendukung semua jenis perangkat (masa depan). Tidak mengherankan, desain ini memanggil elemen baru, elemen <device>, yang menjadi pendahulunya getUserMedia().

Opera adalah salah satu browser pertama yang membuat penerapan awal rekaman video berdasarkan elemen <device>. Segera setelah (tepatnya pada hari yang sama), WhatWG memutuskan untuk menghapus tag <device> demi mendukung versi yang lebih baru dan baru, kali ini JavaScript API yang disebut navigator.getUserMedia(). Seminggu kemudian, Opera merilis build baru yang menyertakan dukungan untuk spesifikasi getUserMedia() yang diupdate. Kemudian pada tahun yang sama, Microsoft ikut serta dengan merilis Lab untuk IE9 yang mendukung spesifikasi baru ini.

Berikut tampilan <device>:

<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
  function update(stream) {
    document.querySelector('video').src = stream.url;
  }
</script>

Dukungan:

Sayangnya, tidak ada browser yang dirilis yang menyertakan <device>. Saya rasa, lebih sedikit API yang perlu dikhawatirkan :) <device> memang memiliki dua hal hebat untuknya: 1.) API itu semantik, dan 2.) mudah diperluas untuk mendukung lebih dari sekadar perangkat audio/video.

Ambil napas. Fitur ini bergerak cepat!

Tahap 3: WebRTC

Elemen <device> pada akhirnya mengikuti jalan Dodo.

Kemampuan untuk menemukan API pengambilan yang sesuai kini dipercepat berkat upaya WebRTC (Web Real Time Communications) yang lebih besar. Spesifikasi tersebut diawasi oleh Grup Kerja WebRTC W3C. Google, Opera, Mozilla, dan beberapa lainnya memiliki implementasi.

getUserMedia() terkait dengan WebRTC karena merupakan gateway ke dalam kumpulan API tersebut. Layanan ini menyediakan cara untuk mengakses streaming kamera/mikrofon lokal pengguna.

Dukungan:

getUserMedia() telah didukung sejak Chrome 21, Opera 18, dan Firefox 17.

Memulai

Dengan navigator.mediaDevices.getUserMedia(), akhirnya kita dapat memanfaatkan input webcam dan mikrofon tanpa plugin. Akses kamera sekarang dapat diakses melalui panggilan jauh, bukan hanya sekali. File ini akan langsung dimasukkan ke dalam browser. Sudah bersemangat?

Deteksi fitur

Mendeteksi fitur adalah pemeriksaan sederhana untuk keberadaan navigator.mediaDevices.getUserMedia:

if (navigator.mediaDevices?.getUserMedia) {
  // Good to go!
} else {
  alert("navigator.mediaDevices.getUserMedia() is not supported");
}

Mendapatkan akses ke perangkat input

Untuk menggunakan webcam atau mikrofon, kita perlu meminta izin. Parameter pertama untuk navigator.mediaDevices.getUserMedia() adalah objek yang menentukan detail dan persyaratan untuk setiap jenis media yang ingin Anda akses. Misalnya, jika Anda ingin mengakses webcam, parameter pertama harus {video: true}. Untuk menggunakan mikrofon dan kamera, teruskan {video: true, audio: true}:

<video autoplay></video>

<script>
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: true })
    .then((localMediaStream) => {
      const video = document.querySelector("video");
      video.srcObject = localMediaStream;
    })
    .catch((error) => {
      console.log("Rejected!", error);
    });
</script>

Oke. Jadi apa yang terjadi? Perekaman media adalah contoh sempurna dari API HTML5 baru yang bekerja sama. Ini berfungsi bersama teman HTML5 kami yang lain, <audio> dan <video>. Perhatikan bahwa kita tidak menetapkan atribut src atau menyertakan elemen <source> pada elemen <video>. Alih-alih memasukkan URL ke file media pada video, kita menyetel srcObject ke objek LocalMediaStream yang mewakili webcam.

Saya juga memberi tahu <video> ke autoplay, jika tidak, kode akan dibekukan di frame pertama. Menambahkan controls juga berfungsi seperti yang Anda harapkan.

Menetapkan batasan media (resolusi, tinggi, lebar)

Parameter pertama untuk getUserMedia() juga dapat digunakan untuk menentukan lebih banyak persyaratan (atau batasan) pada streaming media yang ditampilkan. Misalnya, sebagai ganti hanya menunjukkan bahwa Anda menginginkan akses dasar ke video (misalnya {video: true}), Anda juga dapat mewajibkan streaming tersebut dalam format HD:

const hdConstraints = {
  video: { width: { exact:  1280} , height: { exact: 720 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
const vgaConstraints = {
  video: { width: { exact:  640} , height: { exact: 360 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);

Untuk konfigurasi lainnya, lihat constraints API.

Memilih sumber media

Metode enumerateDevices() dari antarmuka MediaDevices meminta daftar perangkat input dan output media yang tersedia, seperti mikrofon, kamera, headset, dan sebagainya. Promise yang ditampilkan diselesaikan dengan array objek MediaDeviceInfo yang mendeskripsikan perangkat.

Dalam contoh ini, mikrofon dan kamera terakhir yang ditemukan dipilih sebagai sumber streaming media:

if (!navigator.mediaDevices?.enumerateDevices) {
  console.log("enumerateDevices() not supported.");
} else {
  // List cameras and microphones.
  navigator.mediaDevices
    .enumerateDevices()
    .then((devices) => {
      let audioSource = null;
      let videoSource = null;

      devices.forEach((device) => {
        if (device.kind === "audioinput") {
          audioSource = device.deviceId;
        } else if (device.kind === "videoinput") {
          videoSource = device.deviceId;
        }
      });
      sourceSelected(audioSource, videoSource);
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
}

async function sourceSelected(audioSource, videoSource) {
  const constraints = {
    audio: { deviceId: audioSource },
    video: { deviceId: videoSource },
  };
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
}

Lihat demo bagus Sam Dutton tentang cara memungkinkan pengguna memilih sumber media.

Keamanan

Browser menampilkan dialog izin saat memanggil navigator.mediaDevices.getUserMedia(), yang memberi pengguna opsi untuk memberikan atau menolak akses ke kamera/mikrofon. Misalnya, berikut adalah dialog izin Chrome:

Dialog izin di Chrome
Dialog izin di Chrome

Menyediakan penggantian

Bagi pengguna yang tidak memiliki dukungan untuk navigator.mediaDevices.getUserMedia(), salah satu opsinya adalah melakukan penggantian ke file video yang ada jika API tidak didukung dan/atau panggilan gagal karena beberapa alasan:

if (!navigator.mediaDevices?.getUserMedia) {
  video.src = "fallbackvideo.webm";
} else {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true });
  video.srcObject = stream;
}