Recording and Uploading Audio in Web Applications Using JavaScript

A simple example of how to record and upload audio in a web page, using JavaScript.
January 20, 2025 by
Recording and Uploading Audio in Web Applications Using JavaScript
Hamed Mohammadi
| No comments yet

Recording audio directly in web browsers has become increasingly important for modern web applications. Whether you're building a voice messaging system, a podcast platform, or a language learning app, the ability to capture and handle audio is essential. In this post, I'll show you how to implement audio recording, playback, and uploading using vanilla JavaScript.

Prerequisites

Before we dive in, make sure you understand:

  • Basic HTML and JavaScript
  • Async/await and Promises in JavaScript
  • Basic understanding of Web APIs

Understanding the MediaRecorder API

The MediaRecorder API is a key component for recording audio in the browser. It provides a clean interface to capture media streams and create recordings. Here's how it works:

  1. First, we request access to the user's microphone
  2. Then we create a MediaRecorder instance with the audio stream
  3. Finally, we collect the recorded data and convert it into a usable format

Implementation

Let's build a complete audio recorder with these features:

  • Record audio from the microphone
  • Preview the recording
  • Convert to MP3 format
  • Upload to a server

HTML Structure

First, let's create a simple interface:

<!DOCTYPE html>
<html>
<head>
    <title>Audio Recorder</title>
    <style>
        .container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
        }
        .controls {
            margin: 20px 0;
        }
        button {
            margin: 5px;
            padding: 10px 20px;
        }
        #audioPreview {
            width: 100%;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Audio Recorder</h1>
        <div class="controls">
            <button id="recordButton">Start Recording</button>
            <button id="stopButton" disabled>Stop Recording</button>
            <button id="uploadButton" disabled>Upload Recording</button>
        </div>
        <audio id="audioPreview" controls></audio>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lamejs/1.2.1/lame.min.js"></script>
    <script src="audio-recorder.js"></script>
</body>
</html>

JavaScript Implementation

Here's our complete audio-recorder.js:

let mediaRecorder;
let audioChunks = [];

document.getElementById('recordButton').addEventListener('click', startRecording);
document.getElementById('stopButton').addEventListener('click', stopRecording);
document.getElementById('uploadButton').addEventListener('click', uploadRecording);

async function startRecording() {
    audioChunks = [];
    try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        mediaRecorder = new MediaRecorder(stream, {
            mimeType: 'audio/webm'
        });

        mediaRecorder.ondataavailable = (event) => {
            audioChunks.push(event.data);
        };

        mediaRecorder.onstop = async () => {
            const audioBlob = await convertToMp3(new Blob(audioChunks, { type: 'audio/webm' }));
            const audioUrl = URL.createObjectURL(audioBlob);
            document.getElementById('audioPreview').src = audioUrl;
        };

        mediaRecorder.start();
        document.getElementById('recordButton').disabled = true;
        document.getElementById('stopButton').disabled = false;
        document.getElementById('uploadButton').disabled = true;
    } catch (err) {
        console.error('Error accessing microphone:', err);
        alert('Error accessing microphone. Please ensure you have granted permission.');
    }
}

function stopRecording() {
    mediaRecorder.stop();
    mediaRecorder.stream.getTracks().forEach(track => track.stop());
    document.getElementById('recordButton').disabled = false;
    document.getElementById('stopButton').disabled = true;
    document.getElementById('uploadButton').disabled = false;
}

async function convertToMp3(blob) {
    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
    const arrayBuffer = await blob.arrayBuffer();
    const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

    const mp3Encoder = new lamejs.Mp3Encoder(1, audioBuffer.sampleRate, 128);
    const samples = new Int16Array(audioBuffer.length);
    const channel = audioBuffer.getChannelData(0);

    // Convert Float32Array to Int16Array
    for (let i = 0; i < channel.length; i++) {
        samples[i] = channel[i] * 0x7FFF;
    }

    // Encode to MP3
    const mp3Data = [];
    const blockSize = 1152;
    for (let i = 0; i < samples.length; i += blockSize) {
        const sampleChunk = samples.subarray(i, i + blockSize);
        const mp3buf = mp3Encoder.encodeBuffer(sampleChunk);
        if (mp3buf.length > 0) {
            mp3Data.push(mp3buf);
        }
    }

    const mp3buf = mp3Encoder.flush();
    if (mp3buf.length > 0) {
        mp3Data.push(mp3buf);
    }

    return new Blob(mp3Data, { type: 'audio/mp3' });
}

async function uploadRecording() {
    try {
        const audioBlob = await convertToMp3(new Blob(audioChunks, { type: 'audio/webm' }));
        const formData = new FormData();
        formData.append('audio', audioBlob, 'recording.mp3');

        const response = await fetch('/upload-audio', {
            method: 'POST',
            body: formData
        });

        const result = await response.json();
        if (response.ok) {
            alert('Recording uploaded successfully!');
            document.getElementById('uploadButton').disabled = true;
        } else {
            alert('Error uploading recording: ' + result.error);
        }
    } catch (err) {
        console.error('Error uploading recording:', err);
        alert('Error uploading recording. Please try again.');
    }
}

How It Works

Let's break down the key components:

1. Recording Audio

The recording process begins when the user clicks the "Start Recording" button. We use navigator.mediaDevices.getUserMedia() to access the microphone and create a MediaRecorder instance. The recorder stores audio chunks as they become available.

2. Converting to MP3

We use the lame.js library to convert the WebM audio to MP3 format. This involves:

  1. Converting the audio blob to an ArrayBuffer
  2. Decoding the audio data
  3. Converting the float audio data to 16-bit integers
  4. Encoding the data to MP3 format

3. Uploading

The upload process uses the Fetch API to send the MP3 file to the server using FormData. This makes it easy to handle on the server side, regardless of the backend technology you're using.

Browser Compatibility

This implementation works in all modern browsers. However, keep in mind:

  • Safari has some limitations with the MediaRecorder API
  • Older browsers might not support some features
  • Mobile browsers might handle audio permissions differently

Security Considerations

When implementing audio recording:

  1. Always request user permission before accessing the microphone
  2. Use secure connections (HTTPS) for uploading
  3. Implement proper server-side validation
  4. Consider implementing file size limits
  5. Handle user permissions appropriately

Enhancements You Could Add

Here are some ways to enhance this basic implementation:

  • Add recording duration display
  • Implement pause/resume functionality
  • Add audio visualization
  • Include recording quality options
  • Add progress indicators for upload
  • Implement error handling for various network conditions

Conclusion

Recording and handling audio in web applications is now easier than ever with modern Web APIs. This implementation provides a solid foundation that you can build upon for your specific use case. Remember to consider browser compatibility and security implications when deploying to production.

The complete code is available in the examples above. Feel free to modify and enhance it for your specific needs!

in Web
Recording and Uploading Audio in Web Applications Using JavaScript
Hamed Mohammadi January 20, 2025
Share this post
Tags
Archive

Please visit our blog at:

https://zehabsd.com/blog

A platform for Flash Stories:

https://readflashy.com

A platform for Persian Literature Lovers:

https://sarayesokhan.com

Sign in to leave a comment