درحال ضبط کردن صدا از کاربر

اکنون بسیاری از مرورگرها می‌توانند به ورودی صوتی و ویدیویی کاربر دسترسی داشته باشند. بااین‌حال، بسته به مرورگر، ممکن است تجربه‌ای کاملاً پویا و درون‌خطی باشد، یا ممکن است به برنامه دیگری در دستگاه کاربر واگذار شود.

ساده و به‌تدریج شروع کنید

ساده‌ترین کار این است که از کاربر بخواهید فایل ازپیش ضبط‌شده‌ای را ارائه دهد. این کار را با ایجاد یک عنصر ورودی فایل ساده و افزودن فیلتر accept که نشان می‌دهد فقط می‌توانیم فایل‌های صوتی را بپذیریم، و ویژگی capture که نشان می‌دهد می‌خواهیم آن را مستقیماً از میکروفون دریافت کنیم، انجام دهید.

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

این روش در همه پلاتفرم‌ها کار می‌کند. در رایانه، از کاربر خواسته می‌شود فایلی را از سیستم فایل بارگذاری کند (مشخصه capture نادیده گرفته می‌شود). در Safari در iOS، برنامه میکروفون باز می‌شود و به شما امکان می‌دهد صدا ضبط کنید و سپس آن را به صفحه وب برگردانید؛ در Android، به کاربر امکان می‌دهد انتخاب کند که از کدام برنامه برای ضبط صدا استفاده کند و سپس آن را به صفحه وب برگرداند.

وقتی کاربر ضبط را تمام کرد و به وب‌سایت برگشت، باید به‌نحوی به داده‌های فایل دسترسی پیدا کنید. با پیوست کردن رویداد onchange به عنصر ورودی و سپس خواندن ویژگی files شیء رویداد، می‌توانید دسترسی سریع داشته باشید.

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

وقتی به فایل دسترسی پیدا کردید، می‌توانید هر کاری که می‌خواهید با آن انجام دهید. برای مثال، می‌توانید:

  • آن را مستقیماً به عنصر <audio> پیوست کنید تا بتوانید آن را پخش کنید
  • آن را در دستگاه کاربر بارگیری کنید
  • با پیوست کردن آن به XMLHttpRequest، آن را در سرور بارگذاری کنید
  • آن را ازطریق Web Audio API ارسال کنید و فیلترها را روی آن اعمال کنید

درحالی‌که استفاده از روش عنصر ورودی برای دسترسی به داده‌های صوتی همه‌جا رایج است، این گزینه کمترین جذابیت را دارد. ما واقعاً می‌خواهیم به میکروفون دسترسی داشته باشیم و تجربه خوبی را مستقیماً در صفحه ارائه دهیم.

دسترسی به میکروفون به‌صورت تعاملی

مرورگرهای مدرن می‌توانند خط مستقیمی به میکروفون داشته باشند که به ما امکان می‌دهد تجربه‌هایی بسازیم که کاملاً با صفحه وب ادغام شده‌اند و کاربر هرگز مرورگر را ترک نخواهد کرد.

دسترسی به میکروفون را دریافت کنید

بااستفاده از میانای برنامه‌سازی کاربردی در مشخصات WebRTC به‌نام getUserMedia()، می‌توانیم مستقیماً به میکروفون دسترسی پیدا کنیم. getUserMedia() از کاربر درخواست می‌کند به میکروفون‌ها و دوربین‌های متصل‌شده دسترسی داشته باشد.

اگر موفقیت‌آمیز باشد، API یک Stream برمی‌گرداند که حاوی داده‌های دوربین یا میکروفون خواهد بود، و سپس می‌توانیم آن را به عنصر <audio> متصل کنیم، به جریان WebRTC متصل کنیم، به Web Audio AudioContext متصل کنیم، یا بااستفاده از API MediaRecorder ذخیره کنیم.

برای دریافت داده از میکروفون، فقط audio: true را در شیء محدودیت‌ها که به میانای برنامه‌سازی کاربردی getUserMedia() ارسال می‌شود تنظیم می‌کنیم.

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

اگر می‌خواهید میکروفون خاصی را انتخاب کنید، ابتدا می‌توانید میکروفون‌های دردسترس را فهرست کنید.

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

سپس می‌توانید deviceId موردنظرتان را برای استفاده هنگام تماس با getUserMedia ارسال کنید.

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

این به‌تنهایی چندان مفید نیست. تنها کاری که می‌توانیم انجام دهیم این است که داده‌های صوتی را بگیریم و آن را بازپخش کنیم.

دسترسی به داده‌های خام از میکروفون

برای دسترسی به داده‌های خام میکروفون، باید جاری‌سازی ایجادشده توسط getUserMedia() را بگیریم و سپس از Web Audio API برای پردازش داده‌ها استفاده کنیم. ‫Web Audio API یک API ساده است که منابع ورودی را می‌گیرد و آن منابع را به گره‌هایی متصل می‌کند که می‌توانند داده‌های صوتی را پردازش کنند (تنظیم بهره و غیره) و درنهایت به یک بلندگو متصل می‌کند تا کاربر بتواند آن را بشنود.

یکی از گره‌هایی که می‌توانید متصل کنید AudioWorkletNode است. این گره به شما قابلیت سطح پایین برای پردازش سفارشی صدا می‌دهد. پردازش واقعی صدا در روش فراخوانی process() در AudioWorkletProcessor اتفاق می‌افتد. این تابع را برای تغذیه ورودی‌ها و پارامترها و واکشی بروندادها فراخوانی کنید.

برای اطلاعات بیشتر، Enter Audio Worklet را بررسی کنید.

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

داده‌هایی که در میان‌گیرها نگهداری می‌شوند داده‌های خام میکروفون هستند و گزینه‌های متعددی برای کارهایی که می‌توانید با این داده‌ها انجام دهید دارید:

  • آن را مستقیماً در سرور بارگذاری کنید
  • ذخیره کردن آن در دستگاه
  • آن را به قالب فایل اختصاصی، مانند WAV، تبدیل کنید و سپس آن را در سرورهای خود یا به‌صورت محلی ذخیره کنید

ذخیره داده‌های میکروفون

ساده‌ترین راه برای ذخیره کردن داده‌های میکروفون استفاده از MediaRecorder API است.

‫MediaRecorder API جاری‌سازی ایجادشده توسط getUserMedia را می‌گیرد و سپس به‌تدریج داده‌های موجود در جاری‌سازی را در مقصد دلخواه شما ذخیره می‌کند.

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

در مورد ما، داده‌ها را مستقیماً در آرایه‌ای ذخیره می‌کنیم که بعداً می‌توانیم آن را به Blob تبدیل کنیم، که سپس می‌توان از آن برای ذخیره داده‌ها در «سرور وب» یا مستقیماً در فضای ذخیره‌سازی دستگاه کاربر استفاده کرد.

برای استفاده مسئولانه از میکروفون اجازه بگیرید

اگر کاربر قبلاً به سایت شما اجازه دسترسی به میکروفون را نداده باشد، به‌محض اینکه getUserMedia را فراخوانی کنید، مرورگر از کاربر درخواست می‌کند به سایت شما اجازه دسترسی به میکروفون را بدهد.

کاربران از اینکه برای دسترسی به دستگاه‌های قدرتمند در ماشینشان از آن‌ها درخواست شود متنفرند و اغلب درخواست را مسدود می‌کنند، یا اگر زمینه ایجاد درخواست را درک نکنند، آن را نادیده می‌گیرند. بهترین روش این است که فقط زمانی درخواست دسترسی به میکروفون شود که برای اولین‌بار به آن نیاز است. وقتی کاربر دسترسی را اعطا کرد، دیگر از او درخواست نمی‌شود، اما اگر دسترسی را رد کند، نمی‌توانید دوباره از کاربر اجازه بخواهید.

از میانای برنامه‌سازی کاربردی اجازه‌ها استفاده کنید تا بررسی کنید آیا ازقبل دسترسی دارید یا نه

getUserMedia API به شما اطلاع نمی‌دهد که آیا ازقبل به میکروفون دسترسی دارید یا نه. این موضوع مشکلی را برای شما ایجاد می‌کند، برای ارائه یک واسط کاربر خوب برای اینکه کاربر به شما اجازه دسترسی به میکروفون را بدهد، باید دسترسی به میکروفون را درخواست کنید.

این مشکل را می‌توان در برخی‌از مرورگرها بااستفاده از Permission API حل کرد. navigator.permission API به شما امکان می‌دهد وضعیت توانایی دسترسی به میانای برنامه‌سازی کاربردی خاصی را بدون نیاز به درخواست مجدد جستجو کنید.

برای پُرسمان اینکه آیا به میکروفون کاربر دسترسی دارید یا نه، می‌توانید {name: 'microphone'} را به روش پُرسمان ارسال کنید و یکی از موارد زیر را برمی‌گرداند:

  • granted — کاربر قبلاً به شما اجازه دسترسی به میکروفون را داده است؛
  • prompt — کاربر به شما دسترسی نداده است و وقتی با getUserMedia تماس می‌گیرید، از او درخواست می‌شود؛
  • denied — سیستم یا کاربر صریحاً دسترسی به میکروفون را مسدود کرده است و نمی‌توانید به آن دسترسی داشته باشید.

و اکنون می‌توانید به‌سرعت بررسی کنید که آیا لازم است میانای کاربرتان را تغییر دهید تا با کنش‌هایی که کاربر باید انجام دهد سازگار شود یا نه.

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

بازخورد