0

Disclaimer: I am familiar with web technologies but still a newbie.

Scenario: I want user to choose an audio file from local file system. Then I wish to show a small audio control on the webpage to play the selection and send the audio back to the server (after clicking a button).

Problem: Using MatBlazor FileUpload, I am able to get a stream to the local audio file, but I am at a loss on how to use it with the html audio element. Specifically, how can I pass on the audio stream to src in the element?

One clear way to do this in javascript is to use <input type="file"/> element and then use the Filereader() to play the audio. Something like this shown here: Using Filereader.readAsDataURL(), Using URL.createObjectURL()

How can I do this in Blazor, ie play local audio file in browser using stream, the right way?

Current Workaround: For now, I am reading the stream and converting the audio to base64 string and then passing it on to audio element.

The downside of this approach is that for a large audio file of about 18 MB the conversion time is ~30 seconds, and the UI is stuck till then. If I use the javascript way with Interops, then the load time is almost instantaneous, but then I have to use the input element and not the MatFileUpload component. Another reason to have local file stream is because I want to send this audio file to server for further processing and have found it could be done easily using streams.

The code I am using to convert the audio stream to base64 string:

async Task FilesReadyForContent(IMatFileUploadEntry[] files)
    {
        string base64Audio; // variable defined outside the function to update DOM
        bool loadingAudio; // defined outside
        try
        {
            file = files.FirstOrDefault();
            if (file == null)
            {
                base64Audio = "Error! Could not load file";
            }
            else
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    loadingAudio = true;
                    await InvokeAsync(() => this.StateHasChanged());

                    await file.WriteToStreamAsync(ms);
                    base64Audio = System.Convert.ToBase64String(ms.ToArray());

                    loadingAudio = false;
                    await InvokeAsync(() => this.StateHasChanged());
                }
            }
        }
        catch (Exception ex)
        {
            base64Audio = $"Error! Exception:\r\n{ex.Message}\r\n{ex.StackTrace}";
        }
        finally
        {
            await InvokeAsync(() => { this.StateHasChanged(); });
        }
    }
  • It sounds like you are comparing using the built in ` – Kirk Woll Apr 14 '20 at 20:21
  • Agreed that interop isn't a first choice. Currently planning to use interop to invoke `URL.createObjectURL()` to load the audio. Yes, want to also send the audio to server. Looking into how I can do that in a way that's robust enough and can handle relatively large file sizes too (~30 MB). If I can achieve both using interop, then won't want to go through the stream route (which yes, will load the audio in memory). – thebluebloo Apr 15 '20 at 03:07

0 Answers0