Документация Engee
Notebook

Аудио-рекордер

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

  1. Пользователь нажимает кнопку 🎤 → запускается запись
  2. Во время записи:
    • Кнопка становится красной с анимацией
    • Работает таймер
    • Собираются аудиоданные
  3. При остановке:
    • Формируется аудиофайл
    • Появляется плеер и кнопка скачивания
  4. Скачивание создает файл "recording-{дата}.wav"

Подробный разбор кода аудио-рекордера представлен ниже. Код начинается с базовой HTML-структуры и CSS-стилей для красивого интерфейса:

<div class="container">
    <div class="title">Audio Recorder</div>
    <div class="timer" id="timer">00:00</div>
    <button id="recordBtn">🎤</button>
    <button class="download-btn hidden" id="downloadBtn" title="Download recording"></button>
    <div id="status">Press 🎤 to start recording</div>
    <div class="audio-container" id="audioContainer">
        <audio id="audioPlayer" controls></audio>
    </div>
</div>

Ключевые элементы:

  • recordBtn – круглая кнопка записи,
  • downloadBtn – кнопка скачивания (изначально скрыта),
  • timer – отображает время записи,
  • audioPlayer – элемент для воспроизведения записанного аудио.

Далее идёт инициализация переменных

let mediaRecorder;
let audioChunks = [];
let audioBlob;
let audioUrl;
let startTime;
let timerInterval;
let stream;
let isRecording = false;

Переменные хранят состояние приложения:

  • mediaRecorder – объект для записи медиа,
  • audioChunks – массив для хранения записанных данных,
  • audioBlob/audioUrl – итоговое аудио,
  • timerInterval – для обновления таймера,
  • stream – поток данных с микрофона.

После этого объявляются вспомогательные функции

function formatTime(seconds) {
    const mins = Math.floor(seconds / 60).toString().padStart(2, '0');
    const secs = Math.floor(seconds % 60).toString().padStart(2, '0');
    return `${mins}:${secs}`;
}

function updateTimer() {
    const elapsed = Math.floor((Date.now() - startTime) / 1000);
    timerElement.textContent = formatTime(elapsed);
}

formatTime преобразует секунды в формат "MM:SS", а updateTimer обновляет отображение таймера.

Далее идёт функция запуска записи

function startRecording() {
    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(function(s) {
            stream = s;
            mediaRecorder = new MediaRecorder(stream);
            audioChunks = [];
            
            mediaRecorder.ondataavailable = function(e) {
                if (e.data.size > 0) {
                    audioChunks.push(e.data);
                }
            };
            
            mediaRecorder.onstop = function() {
                audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
                audioUrl = URL.createObjectURL(audioBlob);
                audioPlayer.src = audioUrl;
                downloadBtn.classList.remove('hidden');
                statusElement.textContent = "Recording saved! Click 🎤 to record again";
            };
            
            mediaRecorder.start(100);
            startTime = Date.now();
            timerInterval = setInterval(updateTimer, 1000);
            updateTimer();
            isRecording = true;
            recordBtn.classList.add('recording');
            recordBtn.textContent = "⏹️";
            statusElement.textContent = "Recording... Click ⏹️ to stop";
        })
        .catch(function(err) {
            console.error('Error accessing microphone:', err);
            statusElement.textContent = "Error accessing microphone";
        });
}

Логика работы описана далее.

  1. Запрашиваем доступ к микрофону через getUserMedia
  2. Создаем MediaRecorder для записи потока
  3. Настраиваем обработчики:
    • ondataavailable – собирает кусочки аудио,
    • onstop – создает итоговый файл и показывает кнопку скачивания.
  4. Запускаем таймер и меняем интерфейс

После чего реализована остановка записи

function stopRecording() {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop();
        clearInterval(timerInterval);
        stream.getTracks().forEach(track => track.stop());
        isRecording = false;
        recordBtn.classList.remove('recording');
        recordBtn.textContent = "🎤";
    }
}

Останавливает запись, таймер и освобождает ресурсы микрофона.

И скачивание записи:

function downloadRecording() {
    if (audioUrl) {
        const a = document.createElement('a');
        a.href = audioUrl;
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        a.download = `recording-${timestamp}.wav`;
        a.click();
        statusElement.textContent = "Download started...";
    }
}

Создает временную ссылку для скачивания файла с уникальным именем.

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

recordBtn.addEventListener('click', function() {
    if (isRecording) {
        stopRecording();
    } else {
        startRecording();
    }
});

downloadBtn.addEventListener('click', downloadRecording);

Теперь запустим само приложение и посмотрим, как оно работает.

In [ ]:
display("text/html", read("audio_recorder.html", String))
Audio Recorder
Audio Recorder
00:00
Press 🎤 to start recording

Вывод

Этот пример и сам инструмент может быть полезен для генерации тестовых выборок данных для ЦОС.