JavaScript: разрабатываем приложение для записи звука
Привет, друзья!
В этом небольшом «туториале» я хочу показать вам, как разработать приложение для записи и воспроизведения аудио-файлов.
Функционал нашего приложения будет следующим:
- запись аудио
- отображение записи с возможностью ее предварительного прослушивания и последующего сохранения или удаления
- хранение аудио-файлов на сервере
- извлечение аудио-файлов, хранящихся на сервере, и их отображение в браузере
Основная технология, которую мы будем использовать, это MediaDevices
. Данная технология входит в состав глобального объекта Navigator
. Основным методом, предоставляемым указанным интерфейсом является getUserMedia()
. Запись данных (в простых случаях вроде нашего) выполняется с помощью интерфейса MediaRecorder
.
Интерфейс MediaDevices
на сегодняшний день поддерживается всеми современными браузерами.
Для небольшой стилизации нашего приложения мы будем использовать Sass.
Выглядеть приложение примерно так:
Исходный код приложения находится здесь.
Основным источником вдохновения для меня послужила эта замечательная статья.
Обратите внимание: данная статья рассчитана, преимущественно, на начинающих разработчиков, хотя, смею надеяться, что и опытные найдут в ней что-нибудь интересное.
Вы готовы? Тогда вперед!
Начнем с разработки сервера.
Сервер
Создаем директорию для проекта, переходим в нее, инициализируем проект и устанавливаем необходимые зависимости:
# создаем директорию
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('