Build an Audio Recorder with Howler.js

This article provides a step-by-step tutorial on how to build a web-based audio recorder interface. Because Howler.js is designed exclusively for audio playback, you will learn how to combine the browser’s native MediaRecorder API to capture audio with Howler.js to manage and play back your recorded clips.

Understanding the Architecture

Howler.js does not have built-in features to access a user’s microphone or record audio input. To create an audio recorder, you must use a two-part system: 1. The MediaStream Recording API: A native browser API used to capture the audio stream from the user’s microphone and compile it into a data blob. 2. Howler.js: A robust audio library used to load the recorded data blob as a source URL and handle the playback controls (play, pause, stop, volume).

Step 1: Create the HTML Interface

First, set up a simple user interface with three buttons: one to start recording, one to stop recording, and one to play back the captured audio. Include the Howler.js library via CDN.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Audio Recorder</title>
    <!-- Include Howler.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js"></script>
</head>
<body>
    <div id="recorder-container">
        <button id="record-btn">Start Recording</button>
        <button id="stop-btn" disabled>Stop Recording</button>
        <button id="play-btn" disabled>Play Recording</button>
    </div>

    <script src="app.js"></script>
</body>
</html>

Step 2: Implement the JavaScript Logic

In your app.js file, you need to request microphone access, record the incoming audio data chunks, convert those chunks into a playable URL, and initialize Howler.js with that URL.

let mediaRecorder;
let audioChunks = [];
let playbackSound = null;

const recordBtn = document.getElementById('record-btn');
const stopBtn = document.getElementById('stop-btn');
const playBtn = document.getElementById('play-btn');

// 1. Request microphone access and start recording
recordBtn.addEventListener('click', async () => {
    audioChunks = []; // Clear previous recordings
    
    try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        mediaRecorder = new MediaRecorder(stream);
        
        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                audioChunks.push(event.data);
            }
        };

        mediaRecorder.onstop = () => {
            // Convert audio chunks into a single Blob
            const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
            
            // Create a local URL pointing to the Blob
            const audioUrl = URL.createObjectURL(audioBlob);

            // Initialize Howler.js with the Blob URL
            playbackSound = new Howl({
                src: [audioUrl],
                format: ['webm'],
                html5: true // Forces HTML5 Audio, necessary for blob URLs in some browsers
            });

            playBtn.disabled = false;
        };

        mediaRecorder.start();
        recordBtn.disabled = true;
        stopBtn.disabled = false;
        playBtn.disabled = true;
    } catch (err) {
        console.error('Microphone access denied or not supported:', err);
    }
});

// 2. Stop the recording
stopBtn.addEventListener('click', () => {
    mediaRecorder.stop();
    // Stop tracks to release the microphone hardware
    mediaRecorder.stream.getTracks().forEach(track => track.stop());
    
    recordBtn.disabled = false;
    stopBtn.disabled = true;
});

// 3. Play the recording using Howler.js
playBtn.addEventListener('click', () => {
    if (playbackSound) {
        playbackSound.play();
    }
});

Key Considerations