With a little JavaScript Interop you can play mp3 files in your Blazor application.
The first step is to gather a few mp3 files you can play in your app. Remember, these will be playing in the browser, so keep the size of the file in mind. You can download my demo audio files here.
Next, create a new Blazor app with Visual Studio 2019. You can use the free Community Edition if you like.
Next, create a sounds folder under the wwwroot folder, and copy your mp3 files to it. For each file, make sure the Build Action property is set to Content, and the Copy to Output Directory property is set to Copy if newer.
For our demo, we’re going to hijack the Index.razor file, replacing it with the following:
@page "/" @inject IJSRuntime js; <h1>Play MP3 Files</h1> <button class="btn btn-primary" @onclick="PlayAudioFile1">Duh</button> <span> </span> <button class="btn btn-primary" @onclick="PlayAudioFile2">Dwayne</button> <audio id="player"> <source id="playerSource" src="" /> </audio> @code { async Task PlayAudioFile1() { await js.InvokeVoidAsync("PlayAudioFile", "/sounds/duh.mp3"); } async Task PlayAudioFile2() { await js.InvokeVoidAsync("PlayAudioFile", "/sounds/dwayne.mp3"); } }
All we’ve done here is set up a couple buttons to execute code that calls into a JavaScript function called "PlayAudioFile”, which we have yet to write. Let’s do that now.
Open your startup HTML file. In Blazor Server this is Pages/_Host.cshtml and for Blazor WebAssembly it’s wwwroot/Index.html.
Add the following to it, just below the script tag that loads the blazor JavaScript file:
<script> window.PlayAudioFile = (src) => { var audio = document.getElementById('player'); if (audio != null) { var audioSource = document.getElementById('playerSource'); if (audioSource != null) { audioSource.src = src; audio.load(); audio.play(); } } } </script>
This code finds your audio player, sets the source file, loads it, and plays it.
Go ahead and try it.
Play Multiple Audio Files Simultaneously
You’ll notice that if you click the first button, and then the second button immediately, the second mp3 file cuts off the first one. You can fix this in a rather inelegant, yet functional, way.
Create another audio tag for the second mp3 so you can play two simultaneously. More files? Just add more tags. You’ll have to modify your code to handle the change.
Change the contents of Index.razor to this:
@page "/" @inject IJSRuntime js; <h1>Play MP3 Files</h1> <button class="btn btn-primary" @onclick="PlayAudioFile1">Duh</button> <span> </span> <button class="btn btn-primary" @onclick="PlayAudioFile2">Dwayne</button> <audio id="player1"> <source id="playerSource1" src="" /> </audio> <audio id="player2"> <source id="playerSource2" src="" /> </audio> @code { async Task PlayAudioFile1() { await js.InvokeVoidAsync("PlayAudioFile", "1", "/sounds/duh.mp3"); } async Task PlayAudioFile2() { await js.InvokeVoidAsync("PlayAudioFile", "2", "/sounds/dwayne.mp3"); } }
We’ve added a second audio tag, and named them “player1” and “player2”. We’ve also updated the names of the source elements to “playerSource1” and “playerSource2”.
We’ve also modified our JavaScript calls to pass the player number as a string.
Modify your PlayAudioFile JavaScript function to handle the change:
<script> window.PlayAudioFile = (playerNumber, src) => { var audio = document.getElementById('player' + playerNumber); if (audio != null) { var audioSource = document.getElementById('playerSource' + playerNumber); if (audioSource != null) { audioSource.src = src; audio.load(); audio.play(); } } } </script>
Now you have two “channels” with which to play audio files. Great.
Load and play audio dynamically!
Wouldn’t it be great if we didn’t have to provision these audio controls before using them? With a little more JavaScript we can create them on the fly, load the audio file, and play them. Now the audio files will play completely asynchronously.
Change your Index.razor contents back to the first version minus the audio element:
@page "/" @inject IJSRuntime js; <h1>Play MP3 Files</h1> <button class="btn btn-primary" @onclick="PlayAudioFile1">Duh</button> <span> </span> <button class="btn btn-primary" @onclick="PlayAudioFile2">Dwayne</button> @code { async Task PlayAudioFile1() { await js.InvokeVoidAsync("PlayAudioFile", "/sounds/duh.mp3"); } async Task PlayAudioFile2() { await js.InvokeVoidAsync("PlayAudioFile", "/sounds/dwayne.mp3"); } }
Now, let’s change the JavaScript function to create the audio tag, set the properties, add it to the document, load the audio, and play.
window.PlayAudioFile = (src) => { var sound = document.createElement('audio'); sound.src = src; sound.type = 'audio/mpeg'; document.body.appendChild(sound); sound.load(); sound.play(); }
Enjoy!