Kullanıcıdan Ses Kaydetme

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

Basit ve kademeli şekilde başlayın

Yapılacak en kolay şey kullanıcıdan önceden kaydedilmiş bir dosya istemektir. Bunu, basit bir dosya giriş öğesi oluşturup yalnızca ses dosyalarını kabul edebileceğimizi belirten accept filtresi ve bunları doğrudan mikrofondan almak istediğimizi belirten bir capture özelliği ekleyerek yapabilirsiniz.

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

Bu yöntem tüm platformlarda çalışır. Masaüstünde, kullanıcıdan dosya sisteminden dosya yüklemesi istenir (capture özelliği yok sayılır). iOS'teki Safari'de ise mikrofon uygulaması açılır. Böylece sesi kaydedip web sayfasına geri gönderebilirsiniz. Android'de ise sesi web sayfasına geri göndermeden önce sesi hangi uygulamada kaydedeceğini seçme hakkı sunulur.

Kullanıcı kaydı bitirdikten sonra ve tekrar web sitesine girdiğinde, bir şekilde dosya verilerine erişim sağlamanız gerekir. Giriş öğesine bir onchange etkinliği ekleyip ardından etkinlik nesnesinin files özelliğini okuyarak hızlı erişim elde edebilirsiniz.

<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şim elde ettikten sonra dosyayla istediğiniz her şeyi yapabilirsiniz. Örneğin, şunları yapabilirsiniz:

  • Öğeyi oynatabilmek için doğrudan bir <audio> öğesine ekleyin
  • Kullanıcının cihazına indirin
  • Dosyayı bir XMLHttpRequest öğesine ekleyerek sunucuya yükleyin
  • Web Audio API'sından geçirin ve buna filtreler uygulayın

Ses verilerine erişmek için giriş öğesi yönteminin kullanılması yaygın olarak görülse de en az çekici olan seçenektir. Gerçekten mikrofona erişim sağlamak ve doğrudan sayfada güzel bir deneyim sunmak istiyoruz.

Mikrofona etkileşimli olarak erişin

Modern tarayıcılar mikrofona doğrudan bağlanabilen bir bağlantıya sahip olabilir. Bu sayede, web sayfasıyla tamamen entegre edilmiş deneyimler oluşturabiliriz ve kullanıcı tarayıcıdan hiçbir zaman dışarı çıkmaz.

Mikrofona erişim elde edin

WebRTC spesifikasyonunda yer alan getUserMedia() adlı API'yi kullanarak Mikrofon'a doğrudan erişebiliriz. getUserMedia(), kullanıcıdan bağlı mikrofonlarına ve kameralarına erişim izni ister.

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

Mikrofondan veri almak için getUserMedia() API'ye aktarılan kısıtlama nesnesinde audio: true ayarını yapmamı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 mikrofon seçmek istiyorsanız önce kullanılabilir mikrofonları sıralayabilirsiniz.

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

Ardından, getUserMedia numaralı telefonu aradığınızda kullanmak istediğiniz deviceId kartını iletebilirsiniz.

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

Bu yöntem tek başına çok da kullanışlı değildir. Yapabileceğimiz tek şey ses verilerini alıp çalmaktır.

Mikrofondan ham verilere erişme

Mikrofondan ham verilere erişmek için getUserMedia() tarafından oluşturulan akışı alıp Web Audio API'sını kullanarak verileri işlememiz gerekir. Web Audio API, giriş kaynaklarını alan ve bu kaynakları ses verilerini işleyebilen (kazanç ayarlama vb.) düğümlere ve son olarak da kullanıcının duyabilmesi için bir hoparlöre bağlayan basit bir API'dir.

Bağlayabileceğiniz düğümlerden biri AudioWorkletNode. Bu düğüm, düşük seviyeli özel ses işleme özelliği sunar. Gerçek ses işleme, AudioWorkletProcessor içindeki process() geri çağırma yönteminde gerçekleşir. Girişleri ve parametreleri beslemek ve çıkışları getirmek için bu işlevi çağırın.

Daha fazla bilgi edinmek için Ses İş Akışını Girin bölümüne göz atın.

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

Tamponlarda tutulan veriler mikrofondan alınan ham verilerdir ve bu verilerle yapabilecekleriniz için bir dizi seçeneğiniz vardır:

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

Mikrofondaki verileri kaydetme

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

MediaRecorder API, getUserMedia tarafından oluşturulan akışı alır ve ardından akışta bulunan verileri kademeli olarak tercih ettiğiniz hedefe 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>

Örneğimizde, verileri doğrudan bir diziye kaydediyoruz. Bu dizide daha sonra Blob dönüştürüyoruz. Bu dizi daha sonra verileri Web Sunucumuza veya doğrudan kullanıcının cihazındaki depolama alanına kaydetmek için kullanılabiliyor.

Mikrofonu sorumlu bir şekilde kullanmak için izin isteyin

Kullanıcı daha önce sitenizin mikrofona erişmesine izin vermediyse getUserMedia numaralı telefonu çağırdığınız anda tarayıcı, kullanıcıdan sitenize mikrofona erişim izni vermesini ister.

Kullanıcılar makinelerindeki güçlü cihazlara erişimlerinin istenmesinden nefret ederler ve bu isteği sık sık engellerler veya istemin oluşturulduğu bağlamı anlamadıklarında bunu göz ardı ederler. En iyi uygulama, mikrofona yalnızca ilk gerekli olduğunda erişim izni istemektir. Kullanıcı erişim verdikten sonra bu kullanıcıya tekrar sorulmaz ancak kullanıcı erişimi reddederse kullanıcıdan tekrar izin isteyemezsiniz.

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

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

Bu sorun, bazı tarayıcılarda Permission API kullanılarak çözülebilir. navigator.permission API, tekrar sormadan belirli API'lere erişim durumunu sorgulamanıza olanak tanır.

Kullanıcının mikrofonuna erişiminiz olup olmadığını sorgulamak için sorgu yöntemine {name: 'microphone'} geçirebilirsiniz. Bu durumda yöntem şunlardan birini döndürür:

  • granted — kullanıcı daha önce mikrofona erişim izni verdi;
  • prompt — kullanıcı size erişim izni vermedi ve getUserMedia numaralı telefonu aradığınızda bundan sonra sorulacak;
  • denied — Sistem veya kullanıcı, mikrofona erişimi açıkça engelledi. Siz de ona erişemezsiniz.

Ayrıca, kullanıcının yapması gereken işlemleri karşılamak için kullanıcı arayüzünüzü değiştirmeniz gerekip gerekmediğini hızlı bir şekilde 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