Search code examples
c#blazorblazor-client-side

Blazor Client unable to render javascript audio


I'm using VS community 2019, dotnet core 3.1, and signalR. Uploaded proj to gitHUb https://github.com/shane-droid/BlazorSignalRApp note: I'm a complete noob. I've been following tutorials and have read the relevant SO related solutions.

I have a feeling it is something todo with the way I have poorly written the async methods ( because i don't grasp the implementation here]

Dumb down responses and further reading greatly appreciated.

Problem: This piece of code doesn't seem to fire the javascript audio every time a message is received. It fires the timer every time, but the audio only on first message. I placed a button on screen to play the audio manually after first message, then the audio will play on subsequent messages.

the Index.razor has this method:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await JSRuntime.InvokeVoidAsync("PlaySound");
        timer.Start();
    }

    if (!firstRender)
    {
        await JSRuntime.InvokeVoidAsync("PlaySound");
        timer.Start();

    }
}

I am sure (!firstRender) is not the correct approach, but i don't know what is.

The index.html has a javascript

<script type="text/javascript" >
window.PlaySound = function ()
{
    document.getElementById('sound').play();
}

window.PlaySound2 = function ()
{
    document.getElementById('sound').play();
}

USAGE https://localhost:44376/receive?_lane=lane1&name=oneil&ph=0987

Full Index.razor Code: [ for ease of read ]

    @using Microsoft.JSInterop
@inject IJSRuntime JSRuntime;
@page "/"

@using Microsoft.AspNetCore.SignalR.Client
@using System.Timers;


@inject NavigationManager NavigationManager



<hr>

<div> <h1>Lane1</h1></div>
<div style="background-color: @laneColor">    <h1>@lane1Message </h1>  </div>

<hr>

<div> <h1>Lane2</h1></div>
<h1>@lane2Message  </h1>
<hr>
<audio autoplay controls><source src="Sounds/you-have-new-message.wav" /></audio>

@code {
    private HubConnection _hubConnection;
private string lane1Message;
private string lane2Message;
private string laneColor = "red";
private int flashCounter = 0;
private int soundCounter = 0;
Timer timer;



private void elapsedEventHandler(object sender, ElapsedEventArgs e)
{
    if (flashCounter < 11)
    {
        flashCounter++;
        elapsedTimer();
    }
    if (flashCounter == 10)
    {
        timer.Stop();
    }
}

private void elapsedTimer()
{
    if (laneColor == "white")
    {
        laneColor = "yellow";
    }
    else
    {
        laneColor = "white";
    }

    StateHasChanged();
}

protected override void OnInitialized()
{
    timer = new Timer();
    timer.Interval = 500;
    timer.Elapsed += elapsedEventHandler;
}

protected override async Task OnInitializedAsync()
{


    _hubConnection = new HubConnectionBuilder()
        //.WithUrl(NavigationManager.ToAbsoluteUri("/chatHub"))
        .WithUrl(NavigationManager.ToAbsoluteUri("https://localhost:44376/chatHub"))
        .Build();



    _hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
    {
        if (user == "lane1")
        {
            lane1Message = $"{message}" + " Please enter  room";


        }
        if (user == "lane2")
        {
            lane2Message = $"{message}" + " Please enter  room";
        }

        flashCounter = 0;
        soundCounter = 0;

        StateHasChanged();

    });

    await _hubConnection.StartAsync();

}


protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await JSRuntime.InvokeVoidAsync("PlaySound");
        timer.Start();


    }

    if (!firstRender)
    {
        await JSRuntime.InvokeVoidAsync("PlaySound");
        timer.Start();


    }

}


public bool IsConnected =>
_hubConnection.State == HubConnectionState.Connected;

}


Solution

  • You should be aware that browsers behave differently with this kind of thing and you may find it works in e.g. Chrome but not Firefox - or the other way around.

    Anyway some browsers will require user interaction to allow media to play, which might explain why adding a button and clicking it then allowed further sounds to play - you interacted with the page and the browser allowed the audio to play.

    As you have seen the implementations vary and are inconsistent.

    Your code is not at fault, but it's just not going to always work, thankfully or we would all be swamped by autoplaying adverts like a few browser versions ago.