HTML5 ile ses ve video yakalama

Giriş

Ses/video yakalama, uzun zamandır web geliştirmenin en "kutsal kâsesi" olmuştur. Bu işi yapmak için yıllardır tarayıcı eklentilerine (Flash veya Silverlight) güvenmek zorunda kaldık. Hadi!

HTML5'in yardımına ihtiyacınız var. Bu durum açıkça anlaşılamayabilir ancak HTML5'in yükselişi, cihaz donanımına erişimin artmasına neden oldu. Coğrafi Konum (GPS), Orientation API (ivme ölçer), WebGL (GPU) ve Web Audio API (ses donanımı) buna mükemmel örneklerdir. Bu özellikler inanılmaz derecede güçlüdür ve sistemin temel donanım özelliklerinin üzerine yerleştirilmiş yüksek düzey JavaScript API'lerini gösterir.

Bu eğiticide, web uygulamalarının kullanıcının kamerasına ve mikrofonuna erişmesine olanak tanıyan yeni bir GetUserMedia API'si tanıtılmaktadır.

getUserMedia() işlevine giden yol

getUserMedia() API'ye nasıl ulaştığımızın ilginç bir hikayesi var.

"Media Capture API'lerinin" çeşitli varyantları son birkaç yılda gelişti. Birçok kişi web'de yerel cihazlara erişebilmenin gerekliliğini fark etti, ancak bu durum herkesi yeni bir özellik oluşturmaya yöneltti. İşler o kadar karışık bir hal aldı ki W3C sonunda bir çalışma grubu oluşturmaya karar verdi. Tek amaçları bu mu? Bu çılgınlığı anlayın! Cihaz API'leri Politikası (DAP) Çalışma Grubu'na, çok sayıdaki öneriyi birleştirip standartlaştırma görevi verildi.

2011'de neler olduğunu özetlemeye çalışacağım…

1. Tur: HTML Medya Yakalama

HTML Medya Yakalama, DAP'nin web'de medya yakalamayı standartlaştırmaya yönelik ilk denemesidir. Bu yöntem, <input type="file"> parametresini aşırı yükleyerek ve accept parametresine yeni değerler ekleyerek çalışır.

Kullanıcıların web kamerasıyla kendi fotoğraflarını çekmelerine izin vermek istiyorsanız capture=camera ile bunu yapabilirsiniz:

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

Video veya ses kaydı yapmak için:

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

Güzel değil mi? Özellikle dosya girişini yeniden kullanmasından hoşlandım. Anlamsal olarak bu çok mantıklı. Bu "API"nin eksik kaldığı nokta, gerçek zamanlı efektler (ör. canlı web kamerası verilerini <canvas> olarak oluşturma ve WebGL filtreleri uygulama) oluşturma özelliğidir. HTML Medya Yakalama yalnızca bir medya dosyası kaydetmenize veya zamanda anlık görüntü almanıza olanak tanır.

Destek:

  • Android 3.0 tarayıcı: İlk uygulamalardan biridir. Bu özelliğin işleyişini bu videoda görebilirsiniz.
  • Android için Chrome (0.16)
  • Firefox Mobil 10.0
  • iOS6 Safari ve Chrome (kısmi destek)

2. Tur: cihaz öğesi

Birçok kişi HTML Medya Yakalama özelliğinin çok sınırlayıcı olduğunu düşünüyordu. Bu nedenle, (gelecekteki) her tür cihazı destekleyen yeni bir spesifikasyon ortaya çıktı. Beklendiği gibi, tasarım yeni bir öğe (<device> öğesi) gerektiriyordu ve bu öğe de getUserMedia()'in öncüsü oldu.

Opera, <device> öğesine dayalı video yakalama ilk uygulamalarını oluşturan ilk tarayıcılar arasındaydı. Bundan kısa bir süre sonra (tam olarak aynı gün), WhatWG, <device> etiketini kullanımdan kaldırıp onun yerine navigator.getUserMedia() adlı yeni bir JavaScript API'yi kullanmaya karar verdi. Bir hafta sonra Opera, güncellenmiş getUserMedia() spesifikasyonuna destek içeren yeni derlemeler yayınladı. Aynı yılın ilerleyen dönemlerinde Microsoft da yeni spesifikasyonu destekleyen bir IE9 için Lab yayınlayarak partiye katıldı.

<device> şu şekilde görünür:

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

Destek:

Maalesef, yayınlanan hiçbir tarayıcıda <device> bulunamadı. Endişelenmeniz gereken bir API daha azaldı. :) <device>'ün iki önemli özelliği vardı: 1.) anlamsaldı ve 2.) yalnızca ses/video cihazlarını değil, daha fazlasını desteklemek için kolayca genişletilebilirdi.

Derin bir nefes alın. Bu gelişmeler çok hızlı gerçekleşiyor.

3. Tur: WebRTC

<device> öğesi zaman içinde Dodo kuşunun yolunu izledi.

Daha kapsamlı WebRTC (Web Gerçek Zamanlı İletişim) çalışmaları sayesinde uygun bir yakalama API'si bulma hızı arttı. Bu spesifikasyon, W3C WebRTC Çalışma Grubu tarafından denetlenir. Google, Opera, Mozilla ve diğer birkaçının uygulamaları vardır.

getUserMedia(), bu API grubuna giden ağ geçidi olduğundan WebRTC ile ilgilidir. Kullanıcının yerel kamera/mikrofon akışına erişme olanağı sağlar.

Destek:

getUserMedia(), Chrome 21, Opera 18 ve Firefox 17 sürümlerinden itibaren desteklenmektedir.

Başlarken

navigator.mediaDevices.getUserMedia() sayesinde artık web kamerası ve mikrofon girişini eklenti olmadan kullanabiliyoruz. Kamera erişimi artık bir çağrı kadar uzağınızda, yüklemeniz yeterli değil. Doğrudan tarayıcıya yerleştirilmiştir. Heyecanlandınız mı?

Özellik algılama

Özellik algılama, navigator.mediaDevices.getUserMedia öğesinin varlığını kontrol eden basit bir işlemdir:

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

Bir giriş cihazına erişim kazanma

Web kamerasını veya mikrofonu kullanmak için izin istememiz gerekir. navigator.mediaDevices.getUserMedia() için ilk parametre, erişmek istediğiniz her medya türüne ilişkin ayrıntıları ve koşulları belirten bir nesnedir. Örneğin, web kamerasına erişmek istiyorsanız ilk parametre {video: true} olmalıdır. Hem mikrofonu hem de kamerayı kullanmak için {video: true, audio: true} parametresini iletin:

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

Tamam. Peki, neden böyle oldu? Medya yakalama, yeni HTML5 API'lerinin birlikte çalışmasını gösteren mükemmel bir örnektir. Diğer HTML5 arkadaşlarımız <audio> ve <video> ile birlikte çalışır. <video> öğesinde src özelliği ayarlamadığımızı veya <source> öğeleri eklemediğimizi unutmayın. Videonun URL'sini bir medya dosyasına aktarmak yerine, web kamerasını temsil eden LocalMediaStream nesnesine srcObject değerini ayarlıyoruz.

Ayrıca <video>'e autoplay'yi de söylüyorum. Aksi takdirde ilk karede donar. controls eklemek de beklediğiniz gibi çalışır.

Medya kısıtlamalarını ayarlama (çözünürlük, yükseklik, genişlik)

getUserMedia() parametresinin ilk parametresi, döndürülen medya akışıyla ilgili daha fazla koşul (veya kısıtlama) belirtmek için de kullanılabilir. Örneğin, videoya yalnızca temel erişmek istediğinizi belirtmek yerine (ör. {video: true}) yayının HD olmasını da isteyebilirsiniz:

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

Diğer yapılandırmalar için restrictionts API'ye göz atın.

Medya kaynağı seçme

MediaDevices arayüzünün enumerateDevices() yöntemi, mikrofon, kamera, kulaklık vb. gibi mevcut medya giriş ve çıkış cihazlarının listesini ister. Döndürülen Promise, cihazları açıklayan bir MediaDeviceInfo nesnesi dizisiyle çözülür.

Bu örnekte, bulunan son mikrofon ve kamera medya akışı kaynağı olarak seçilmiştir:

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

Kullanıcıların medya kaynağını seçmelerine izin vermeyle ilgili Sam Dutton'un harika demosuna göz atın.

Güvenlik

Tarayıcılar, navigator.mediaDevices.getUserMedia() çağrıldıktan sonra kullanıcılara kameralarına/mikrofonlarına erişim izni verme veya reddetme seçeneği sunan bir izin iletişim kutusu gösterir. Örneğin, Chrome'un izin iletişim kutusu aşağıda verilmiştir:

Chrome&#39;daki izin iletişim kutusu
Chrome'daki izin iletişim kutusu

Yedek sağlama

navigator.mediaDevices.getUserMedia() desteği olmayan kullanıcılar için API desteklenmiyorsa ve/veya çağrı bir nedenle başarısız olursa mevcut bir video dosyasına yedek olarak başvurabilirsiniz:

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