JavaScript: разрабатываем приложение для записи звука

cmcxbpt9gexnyftfg1tcb7cmbny.jpeg


Привет, друзья!

В этом небольшом «туториале» я хочу показать вам, как разработать приложение для записи и воспроизведения аудио-файлов.

Функционал нашего приложения будет следующим:


  • запись аудио
  • отображение записи с возможностью ее предварительного прослушивания и последующего сохранения или удаления
  • хранение аудио-файлов на сервере
  • извлечение аудио-файлов, хранящихся на сервере, и их отображение в браузере

Основная технология, которую мы будем использовать, это MediaDevices. Данная технология входит в состав глобального объекта Navigator. Основным методом, предоставляемым указанным интерфейсом является getUserMedia(). Запись данных (в простых случаях вроде нашего) выполняется с помощью интерфейса MediaRecorder.

Интерфейс MediaDevices на сегодняшний день поддерживается всеми современными браузерами.

Для небольшой стилизации нашего приложения мы будем использовать Sass.

Выглядеть приложение примерно так:


image-loader.svg

Исходный код приложения находится здесь.

Основным источником вдохновения для меня послужила эта замечательная статья.

Обратите внимание: данная статья рассчитана, преимущественно, на начинающих разработчиков, хотя, смею надеяться, что и опытные найдут в ней что-нибудь интересное.

Вы готовы? Тогда вперед!

Начнем с разработки сервера.


Сервер

Создаем директорию для проекта, переходим в нее, инициализируем проект и устанавливаем необходимые зависимости:

# создаем директорию
mkdir record-app
# переходим в нее
cd !$

# инициализируем проект
# `-y` означает выбор значений по умолчанию
yarn init -y
# или
npm init -y

# устанавливаем основные зависимости
yarn add express multer
# или
npm i ...

# устанавливаем зависимости для разработки
yarn add concurrently nodemon open-cli sass

Зависимости:


  • express — фреймворк для Node.js, облегчающий разработку REST API
  • multer — обертка над busboy для разбора данных в формате multipart/form-data, часто используемая для сохранения файлов
  • concurrently — утилита для одновременного выполнения команд, определенных в package.json
  • nodemon — утилита для запуска сервера для разработки (сервера, который автоматически перезапускается при изменении наблюдаемых файлов)
  • open-cli — утилита для автоматического открытия вкладки браузера по указанному адресу
  • sass — утилита для преобразования SASS в CSS

Определяем команды для запуска сервера для разработки в package.json:

"scripts": {
 "sass": "sass --no-source-map --watch public/style.scss:public/style.css",
 "server": "open-cli http://localhost:3000 && nodemon index.js",
 "start": "concurrently \"yarn sass\" \"yarn server\""
}

Команды:


  • команда sass запускает утилиту для преобразования файла public/style.scss в файл public/style.css в режиме реального времени (--watch) и без создания карты источников (--no-source-map)
  • команда server запускает сервер для разработки и открывает вкладку браузера по адресу http://localhost:3000
  • команда start выполняет команды sass и server

В коде сервера мы будем использовать ES6-модули (import/export), поэтому определим в package.json тип основного файла сервера как модуль:

"type": "module"

В качестве альтернативы для кода сервера можно использовать файл с расширением .mjs.

Давайте определимся со структурой проекта:

- record-app
 - node_modules
 - public - директория со статическими файлами (клиент)
   - img
     - microphone.png
     - pause.png
     - play.png
     - stop.png
   - index.html
   - script.js
   - style.scss
 - uploads - директория для аудио-файлов
 - index.js - сервер
 - package.json

Изображения, которые мы будем использовать при разработке приложения, можно скачать здесь.

Приступаем к реализации.

Что должен уметь наш сервер? Многого от него не требуется: все, что он должен уметь — это обслуживать статические файлы из директорий public и uploads, а также сохранять и извлекать аудио-файлы.

Импортируем необходимые модули:

import express from 'express'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { promises as fs } from 'fs'
import multer from 'multer'

Определяем абсолютный путь к текущей (рабочей) директории:

const __dirname = dirname(fileURLToPath(import.meta.url))

Настраиваем multer:

const upload = multer({
 storage: multer.diskStorage({
   // директория для файлов
   destination(req, file, cb) {
     cb(null, 'uploads/')
   },
   // названия файлов
   filename(req, file, cb) {
     cb(null, `${file.originalname}.mp3`)
   }
 })
})

Создаем приложение express и определяем директории со статическими файлами:

const app = express()
app.use(express.static('public'))
app.use(express.static('uploads'))

Определяем маршрут для сохранения аудио с помощью multer, используемого в качестве посредника (middleware). Аудио будет отправляться методом POST в формате multipart/form-data по адресу /save:

// поле, содержащее файл, должно называться `audio`
app.post('/save', upload.single('audio'), (req, res) => {
 // в ответ мы возвращаем статус `201`,
 // свидетельствующий об успешном сохранении файла на сервере
 res.sendStatus(201)
})

Определяем «роут» для извлечения сохраненных аудио и их отправки клиенту (метод — GET, адрес — /records):

app.get('/records', async (req, res) => {
 try {
   // читаем содержимое директории `uploads`
   let files = await fs.readdir(`${__dirname}/uploads`)
   // нас интересуют только файлы с расширением `.mp3`
   files = files.filter((fileName) => fileName.split('.')[1] === 'mp3')
   // отправляем файлы клиенту
   res.status(200).json(files)
 } catch (e) {
   console.log(e)
 }
})

Наконец, определяем порт (по умолчанию 3000) и запускаем сервер:

const port = process.env.PORT || 3000
app.listen(port, () => {
 console.log('
    
            

© Habrahabr.ru