Illustration of a woman standing next to a computer screen that displays an upload icon. She is placing a black file with a play button onto the screen. Below, there is a loading bar with the text "Upload..." indicating a file upload process. The background is light blue, with some minimalistic decor elements like plants and picture frames. Text at the bottom reads "Record and Upload Audio Using Laravel" with a website link "200oksolutions.com" below it.

How to Record and Upload Audio Using Laravel: A Step-by-Step Guide

Share this post on:

In today’s web applications, adding multimedia features can significantly enhance user experience. One such feature is the ability to record and upload audio. In this blog post, we will guide you through the process of recording audio using the browser, uploading it to a Laravel backend, and displaying it on a web page. We’ll cover everything from setting up the Laravel controller to handling audio recording in the browser.

Step 1: Setting Up Laravel

Before we dive into the code, make sure you have a Laravel application set up. If you don’t have one yet, you can create a new Laravel project by running:

composer create-project --prefer-dist laravel/laravel example_audio

Step 2: Database Migration

First, create a migration for storing audio file information. Run the following command:

php artisan make:migration create_audio_files_table

In the generated migration file, define the schema:


public function up()
{
    Schema::create('audio_files', function (Blueprint $table) {
        $table->id();
        $table->string('file_path');
        $table->timestamps();
    });
}
    

Run the migration using the below command:

php artisan migrate

Step 3: Create the Model

Create a model for AudioFile:

php artisan make:model AudioFile

Step 4: Setting Up Routes

Define routes for listing, storing, and deleting audio files in routes/web.php and routes/api.php:


// routes/web.php
Route::get('/audio/list', [AudioController::class, 'list'])->name('audio.list');
Route::post('/api/upload-audio', [AudioController::class, 'store']);
Route::delete('/audio/{id}', [AudioController::class, 'destroy'])->name('audio.destroy');
    

Step 5: Implementing the AudioController

Create the AudioController:

php artisan make:controller AudioController

Here’s the complete code for AudioController:


validate([
            'audio' => 'required|mimes:webm|max:10240'
        ]);
 
        $path = $request->file('audio')->store('audio_files', 'public');
 
        $audio = new AudioFile();
        $audio->file_path = $path;
        $audio->save();
 
        return response()->json(['path' => Storage::url($path)], 200);
    }
 
    public function destroy($id)
    {
        $audio = AudioFile::findOrFail($id);
        
        // Delete the file from storage
        if (Storage::exists($audio->file_path)) {
            Storage::delete($audio->file_path);
        }
 
        $audio->delete();
 
        return redirect()->route('audio.list')->with('status', 'Audio file deleted successfully.');
    }
}
    

Step 6: Building the Frontend

Create the recording and uploading UI in resources/views/audio/voice.blade.php:

<!DOCTYPE html> 

<html lang="en"> 

<head> 

    <meta charset="UTF-8"> 

    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 

    <title>Voice Recording</title> 

    <link rel="stylesheet" href="{{ asset('css/style.css') }}"> 

</head> 

<body> 

    <h1>Record and Upload Audio</h1> 

    <button id="startRecording">Start Recording</button> 

    <button id="stopRecording" disabled>Stop Recording</button> 

    <button id="goToUploads">View Uploaded Files</button> 

    <audio id="audioPlayback" controls></audio> 

    <script> 

        let mediaRecorder; 

        let audioChunks = []; 

        document.getElementById('startRecording').addEventListener('click', () => { 

            navigator.mediaDevices.getUserMedia({ audio: true }) 

                .then(stream => { 

                    mediaRecorder = new MediaRecorder(stream); 

                    mediaRecorder.start(); 

                    document.getElementById('startRecording').disabled = true; 

                    document.getElementById('stopRecording').disabled = false; 

                    mediaRecorder.addEventListener('dataavailable', event => { 

                        audioChunks.push(event.data); 

                    }); 

                    mediaRecorder.addEventListener('stop', () => { 

                        const audioBlob = new Blob(audioChunks); 

                        const audioUrl = URL.createObjectURL(audioBlob); 

                        const audio = document.getElementById('audioPlayback'); 

                        audio.src = audioUrl; 

                        uploadAudio(audioBlob); 

                    }); 

                }); 

        }); 

        document.getElementById('stopRecording').addEventListener('click', () => { 

            mediaRecorder.stop(); 

            document.getElementById('startRecording').disabled = false; 

            document.getElementById('stopRecording').disabled = true; 

        }); 

        document.getElementById('goToUploads').addEventListener('click', () => { 

            window.location.href = '/audio/list'; 

        }); 

        function uploadAudio(audioBlob) { 

            const formData = new FormData(); 

            formData.append('audio', audioBlob, 'voice-recording.webm'); 

            fetch('/api/upload-audio', { 

                method: 'POST', 

                body: formData, 

                headers: { 

                    'X-CSRF-TOKEN': '{{ csrf_token() }}', 

                }, 

            }) 

            .then(response => response.json()) 

            .then(data => { 

                console.log('Audio uploaded successfully:', data); 

                window.location.href = '/audio/list'; 

            }) 

            .catch(error => console.error('Error uploading audio:', error)); 

        } 

    </script> 

</body> 

</html> 

Create the audio list view in resources/views/audio/list.blade.php: 

<!DOCTYPE html> 

<html lang="en"> 

<head> 

    <meta charset="UTF-8"> 

    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 

    <title>Audio Files</title> 

    <link rel="stylesheet" href="{{ asset('css/style.css') }}"> 

</head> 

<body> 

    <div class="container"> 

        <h1>Uploaded Audio Files</h1> 

        <ul> 

            @foreach($audios as $audio) 

                <li> 

                    <audio controls> 

                        <source src="{{ Storage::url($audio->file_path) }}" type="audio/mp3"> 

                        Your browser does not support the audio element. 

                    </audio> 

                    <div class="button-group"> 

                        <a href="{{ Storage::url($audio->file_path) }}" class="btn" download>Download</a> 

                        <form action="{{ route('audio.destroy', $audio->id) }}" method="POST" style="display: inline;"> 

                            @csrf 

                            @method('DELETE') 

                            <button type="submit" class="btn">Delete</button> 

                        </form> 

                    </div> 

                </li> 

            @endforeach 

        </ul> 

        <a href="/voice-record" class="btn back-btn">Back to Recording</a> 

    </div> 

</body> 

</html> 

Step 7: Configuring the Filesystem

Ensure you have the symbolic link created to serve files from the public directory. Run:

php artisan storage:link

This command creates a symbolic link from public/storage to storage/app/public, allowing you to access files through URLs.

Conclusion

In this guide, we covered how to integrate audio recording and uploading functionality into a Laravel application. We implemented a backend to handle audio file storage and deletion and created a frontend to allow users to record, upload, and manage their audio files. With these components in place, you can enhance your Laravel applications with rich multimedia features. Happy coding!