Запись звука JS c микрофона или голосовые комментарии

Запись звука JS c микрофона или голосовые комментарии

Не давно, при разработке одного корпоративного веб-приложения, заказчик пожелал иметь возможность оставлять голосовые комментарии. Ранее мне не приходил сталкиваться с созданием медиаконтента и я с интересом приступил к изучению данной темы.

В сети предоставлено достаточно справочной информации по теме создания и обработки такого рода контента, однако я не нашел простого, полноценно работающего примера. После реализации поставленной задачи заказчиком, решил опубликовать максимально упрощенный пример записи и сохранения голосового комментария и написать статью. Возможно, этот материал будет кому-то полезен и поможет в изучении.

Постановка задачи

Поставим себе задачу разработать мини приложение, работающее в браузере, которое позволит записать голосовой комментарий, отправить запись на сервер, сервер сохранит запись, в случае успеха вернет ответ с именем созданного файла и отобразит объект на странице для того чтоб запись можно было прослушать.

Запись звука в браузере

Запись звука было решено реализовать с помощью интерфейса веб API MediaStream Recording. Для записи воспользуемся интерфейсом MediaRecorder(). Но прежде создадим интерфейс. Пусть у нас будет index.html содержащий лишь самые основные теги, а в теле тега подключим файл с нашим будущим JavaScript-ом voice.js:

<!DOCTYPE html> <head>     <meta charset="UTF-8">     <title>Voice comments</title> </head> <body>     <script src="voice.js"></script> </body> </html>

Создадим файл voice.js, определим в нем константу URL которая будет содержать ссылку на скрипт принимающий записанный звук. Далее создадим кнопки Start и Stop для начала и остановки записи звука, а так же блок div в котором будут отображаться сохраненные записи. На этом наш интерфейс готов, можно приступить непосредственно к записи звука.

Как уже говорилось для записи воспользуемся интерфейсом MediaRecorder()(подробнее об интерфейсе можно узнать из документации), для его работы необходимо определить медиа поток с которого будем брать звук, инициализируем его лишь то что нам нужна только audio дорожка.

navigator.mediaDevices.getUserMedia({ audio: true})     .then(stream => {         const mediaRecorder = new MediaRecorder(stream)}); 

Теперь у нас есть константа mediaRecorder, которая содержит экземпляр интерфейса, с ней и будем далее работать.

Для начала записи нам нужно вызвать метод MediaRecorder.start(), для остановки записи метод MediaRecorder.stop(). При этом MediaRecorder.stop() генерирует событие dataavailable через которое мы получим доступ оцифрованной звукозаписи в виде бинарного массива.

И так опишем выше указанные события, объявим массив voice[] и запишем в него полученные данные:

navigator.mediaDevices.getUserMedia({ audio: true})     .then(stream => {         const mediaRecorder = new MediaRecorder(stream);         let voice = [];         document.querySelector('#start').addEventListener('click', function(){             mediaRecorder.start();         });          mediaRecorder.addEventListener("dataavailable",function(event) {             voice.push(event.data);         });          document.querySelector('#stop').addEventListener('click', function(){             mediaRecorder.stop();         });     }); 

Теперь подготовим полученные данные к отправке. Для этого, по событию stop, создадим экземпляр BLOB, поместим в него полученные данные и укажем MIME тип данных. В нашем случае это будет audio/wav.

mediaRecorder.addEventListener("stop", function() {     const voiceBlob = new Blob(voice, {         type: 'audio/wav'     }); 

В результате мы имеем константу voiceBlob в которой, находится содежримое нашего будущего фала wav с записью голосового сообщения.

Отправка записи на сервер

Для отправки записи на сервер я решил использовать метод fetch(). Так как данный метод является наиболее современным и предоставляет улучшенный интерфейс для осуществления запросов к серверу. В рамках нашей задачи нам нужно инициировать POST запрос в теле которого отправить содержимое нашего будущего файла для сохранения на сервере (как работает и какими возможностями обладает метод fetch(), можно подробно ознакомиться в документации). Создадим новую форму с полем voice и поместим в него содержимое нашей записи.

let fd = new FormData(); fd.append('voice', voiceBlob); 

Создадим асинхронную функцию отправки сообщения на сервер получения ответа и отображения объекта audio для проигрывания уже сохраненного файла. В качестве аргумента функция будет принимать созданную выше форму.

Инициируем запрос к серверу:

let promise = await fetch(URL, {     method: 'POST',     body: form}); 

Если HTTP ответ от сервера не содержит кода ошибки (код ответа в диапазоне от 200-299), то нам остается декодировать ответ, создать на странице новый объект audio, определить его свойства и отобразить. Как формируется ответ, будет рассмотрено ниже.

Сохранение файла на сервере

Создадим на сервере скрипт, который будет принимать наш POST запрос с голосовым сообщением. Так как отправленное нами звукозапись по сути уже является файлом в форме, мы его будем получать на сервере соответствующим образом:

$uploadDir = 'voice/'; $typeFile = explode('/', $_FILES['voice']['type']); $uploadFile = $uploadDir . basename(md5($_FILES['voice']['tmp_name'].time()).'.'.$typeFile[1]); if (move_uploaded_file($_FILES['voice']['tmp_name'], $uploadFile)) {     $response = ['result'=>'OK', 'data'=>'../'.$uploadFile]; } else {     $response = ['result'=>'ERROR', 'data'=>'']; } echo json_encode($response); 

Подобных примеров PHP кода, обработки полученных файлов, в сети можно найти очень много. Для начала инициализируем переменные, $uploadDir – каталог в котором будет сохранен полученный файл, тип файла &typeFile в нашем случае будет равно wav и полное имя файла, включая директорию. Имя файла в данном случае формируется путем объединения «временного» имени файла и строчного значения текущего времени зашифрованного методом md5. В случае удачного сохранения файла с голосовым сообщением в указанном каталоге формируем ответ в виде массива содержащего поле result равное «OK» или «ERROR» в зависимости от результата и поле «data» которое, в случае успешной обработки содержит ссылку на сохраненный файл.

Для удобства массив преобразуем в объект JSON и отправляем в качестве ответа.

Полный код примера размещен на GitHub.

P.S. Браузер позволяет записывать медиаконтент только при безопасном HTTPS подключении.

ссылка на оригинал статьи https://habr.com/ru/post/484196/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *