ضبط صدا از کاربر

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

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

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

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

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

هنگامی که کاربر ضبط را تمام کرد و دوباره به وب سایت بازگشت، باید به نحوی از داده های فایل مطلع شوید. می‌توانید با پیوست کردن یک رویداد 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 عبور دهید و فیلترهایی را روی آن اعمال کنید

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

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

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

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

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

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

برای دریافت داده‌ها از میکروفون، فقط audio: true در شیء constraints که به API 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 ساده است که منابع ورودی را می گیرد و آن منابع را به گره هایی که می توانند داده های صوتی را پردازش کنند (تنظیم Gain و غیره) و در نهایت به یک بلندگو متصل می کند تا کاربر بتواند آن را بشنود.

یکی از گره هایی که می توانید متصل کنید AudioWorkletNode است. این گره قابلیت سطح پایینی برای پردازش صوتی سفارشی را به شما می دهد. پردازش واقعی صدا در process() callback در 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 صدا می‌زنید، مرورگر از کاربر می‌خواهد تا به سایت شما اجازه میکروفون بدهد.

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

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

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

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

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

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

بازخورد