Kullanıcıdan Ses Kaydetme

Birçok tarayıcı artık kullanıcıdan gelen video ve ses girişine erişebiliyor. Ancak tarayıcıya bağlı olarak bu deneyim tamamen dinamik ve satır içi olabilir veya kullanıcının cihazındaki başka bir uygulamaya devredilebilir.

Basit ve kademeli bir başlangıç yapın

En kolay yöntem, kullanıcıdan önceden kaydedilmiş bir dosya istemektir. Bunu yapmak için basit bir dosya girişi öğesi oluşturun ve yalnızca ses dosyalarını kabul edebileceğimizi belirten bir accept filtresi ve doğrudan mikrofondan almak istediğimizi belirten bir capture özelliği ekleyin.

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

Bu yöntem tüm platformlarda kullanılabilir. Masaüstünde, kullanıcıdan dosya sisteminden dosya yüklemesi istenir (capture özelliği yoksayılır). iOS'teki Safari'de mikrofon uygulaması açılır ve ses kaydedip web sayfasına geri gönderebilirsiniz. Android'de ise kullanıcıya, sesi kaydedip web sayfasına geri göndermeden önce hangi uygulamayı kullanacağını seçme seçeneği sunulur.

Kullanıcı kaydı tamamlayıp web sitesine geri döndüğünde, dosya verilerini bir şekilde almanız gerekir. Giriş öğesine bir onchange etkinliği ekleyerek ve ardından etkinlik nesnesinin files mülkünü okuyarak hızlıca erişebilirsiniz.

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

Dosyaya eriştikten sonra istediğiniz işlemi yapabilirsiniz. Örneğin, şunları yapabilirsiniz:

  • Oynayabilmek için doğrudan bir <audio> öğesine ekleyin.
  • Kullanıcının cihazına indirin
  • XMLHttpRequest dosyasına ekleyerek bir sunucuya yükleyin.
  • Web Audio API'den geçirip filtreler uygulayın

Ses verilerine erişmek için giriş öğesi yöntemini kullanmak yaygın olsa da bu yöntem en az ilgi çekici seçenektir. Mikrofona erişmek ve doğrudan sayfada güzel bir deneyim sunmak istiyoruz.

Mikrofonu etkileşimli olarak kullanma

Modern tarayıcılar, mikrofonla doğrudan bağlantı kurabilir. Bu sayede, web sayfasıyla tamamen entegre olan ve kullanıcının tarayıcıdan hiç ayrılmadığı deneyimler oluşturabiliriz.

Mikrofona erişim elde etme

WebRTC spesifikasyonundaki getUserMedia() adlı bir API'yi kullanarak mikrofona doğrudan erişebiliriz. getUserMedia(), kullanıcıdan bağlı mikrofonlara ve kameralara erişim izni ister.

API başarılı olursa kameradan veya mikrofondan gelen verileri içeren bir Stream döndürür. Ardından bu Stream öğesini bir <audio> öğesine, WebRTC akışına, Web Audio AudioContext öğesine ekleyebilir veya MediaRecorder API'yi kullanarak kaydedebiliriz.

Mikrofondan veri almak için getUserMedia() API'ye iletilen constraints nesnesinde audio: true değerini ayarlamamız yeterlidir.

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

Belirli bir mikrofonu seçmek istiyorsanız önce mevcut mikrofonları listeleyebilirsiniz.

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

Ardından, getUserMedia'u aradığınızda kullanmak istediğiniz deviceId'yi iletebilirsiniz.

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

Bu bilgi tek başına çok faydalı değildir. Tek yapabileceğimiz, ses verilerini alıp tekrar oynatmaktır.

Mikrofondaki ham verilere erişim

Mikrofondan alınan ham verilere erişmek için getUserMedia() tarafından oluşturulan akışı almamız ve ardından verileri işlemek için Web Audio API'yi kullanmamız gerekir. Web Audio API, giriş kaynaklarını alıp bu kaynakları ses verilerini işleyebilecek (ör. kazancı ayarlayabilecek) düğümlere ve nihayetinde kullanıcının duyabilmesi için bir hoparlöre bağlayan basit bir API'dir.

Bağlanabileceğiniz düğümlerden biri AudioWorkletNode'tır. Bu düğüm, özel ses işleme için düşük düzeyde bir özellik sunar. Gerçek ses işleme, AudioWorkletProcessor içindeki process() geri çağırma yönteminde gerçekleşir. Giriş ve parametreleri beslemek ve çıkışları almak için bu işlevi çağırın.

Daha fazla bilgi edinmek için Ses İşleyicisi'ni kullanma başlıklı makaleyi inceleyin.

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

Arabelleklerde tutulan veriler, mikrofondan gelen ham verilerdir ve bu verilerle yapabileceğiniz çeşitli işlemler vardır:

  • Doğrudan sunucuya yükleyin
  • Yerel olarak depolama
  • WAV gibi özel bir dosya biçimine dönüştürün ve ardından sunucularınıza veya yerel olarak kaydedin

Mikrofondan gelen verileri kaydetme

Mikrofondan gelen verileri kaydetmenin en kolay yolu MediaRecorder API'yi kullanmaktır.

MediaRecorder API, getUserMedia tarafından oluşturulan akışı alır ve ardından akıştaki verileri tercih ettiğiniz hedefe kademeli olarak kaydeder.

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

Bizim durumumuzda, verileri doğrudan bir diziye kaydediyoruz. Bu diziyi daha sonra Blob olarak dönüştürebiliriz. Blob, verileri web sunucumuza veya doğrudan kullanıcının cihazındaki depolama alanına kaydetmek için kullanılabilir.

Mikrofonu sorumlu bir şekilde kullanmak için izin isteme

Kullanıcı daha önce sitenize mikrofon erişimi vermemişse getUserMedia işlevini çağırdığınız anda tarayıcı, kullanıcıdan sitenize mikrofon erişimi vermesini ister.

Kullanıcılar, makinelerindeki güçlü cihazlara erişim isteğinde bulunulmasından nefret eder ve isteği sık sık engeller ya da istemin oluşturulduğu bağlamı anlamazlarsa yoksayar. Mikrofon erişimi için yalnızca ilk kez ihtiyaç duyulduğunda izin istemek en iyi uygulamadır. Kullanıcı erişim izni verdikten sonra bu istek tekrar gösterilmez. Ancak erişim iznini reddederse kullanıcıdan tekrar izin isteğinde bulunamazsınız.

Erişiminiz olup olmadığını kontrol etmek için izinler API'sini kullanın

getUserMedia API, mikrofon erişiminiz olup olmadığı hakkında bilgi sağlamaz. Bu durum size bir sorun teşkil eder. Kullanıcının mikrofona erişim izni vermesini sağlamak için güzel bir kullanıcı arayüzü sunmanız gerekir.

Bu sorun, bazı tarayıcılarda Permission API kullanılarak çözülebilir. navigator.permission API, belirli API'lere erişme yeteneğiyle ilgili durumu tekrar istemek zorunda kalmadan sorgulamanıza olanak tanır.

Kullanıcının mikrofonuna erişiminizin olup olmadığını sorgulamak için sorgu yöntemine {name: 'microphone'} değerini iletebilirsiniz. Bu yöntem aşağıdakilerden birini döndürür:

  • granted: Kullanıcı daha önce size mikrofona erişim izni verdiyse;
  • prompt: Kullanıcı size erişim izni vermemişse getUserMedia'i aradığınızda izin istenir.
  • denied: Sistem veya kullanıcı mikrofon erişimini açıkça engellemiştir ve mikrofonu kullanamazsınız.

Artık kullanıcı arayüzünüzü, kullanıcının yapması gereken işlemlere uygun olacak şekilde değiştirmeniz gerekip gerekmediğini hızlıca kontrol edebilirsiniz.

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

Geri bildirim