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!