BeautifulPilgrim / MauiAudio

MIT License
23 stars 5 forks source link

Event for whenever the position is updated #9

Closed MrScottyTay closed 1 year ago

MrScottyTay commented 1 year ago

for an example usage I have an app with a waveform image and I was wanting to scroll it as the audio played, at the moment I can only get the current position when the page re-renders via other means.

MrScottyTay commented 1 year ago

I got around this by using requestAnimationFrame with JS interop to call the correct functions in the c# side to get what I needed to be updated

Calling this after calling PlayAsync()

await JS.InvokeAsync<string>("initUpdatePosition", DotNetObjectReference.Create(this));

.js

var DotnetHelper;
function initUpdatePosition(dotnetHelper) {
    DotnetHelper = dotnetHelper;
    updatePosition();
}

function updatePosition() {
    var isPlaying = DotnetHelper.invokeMethodAsync('IsPlaying')
    DotnetHelper.invokeMethodAsync('UpdatePosition');

    if (isPlaying) {
        window.requestAnimationFrame(updatePosition);
    }
}

Edit: Check my updated code in my next comment, this block of code will run indefinitely and may cause trouble down the line

back in the page code

[JSInvokable]
    public bool IsPlaying() => Audio.IsPlaying;

    public double Position { get; set; } = 0;
    [JSInvokable]
    public void UpdatePosition()
    {
        Position = Audio.CurrentPosition;
        StateHasChanged();
    }

This isn't something I was aware of before I posted the original issue, but in case others on the journey of learning MAUI Blazor Hybrid come up with similar issues, here's how I sorted it.

MrScottyTay commented 1 year ago

Here's a slightly updated version of the JS side of my solution that will retry if isPlaying is false (as sometimes this may actually get triggered before IsPlaying has actually had a chance to change), 2 retries seems to be the sweet spot, but you can obviously change that value accordingly if you find otherwise.

var DotnetHelper;
function initUpdatePosition(dotnetHelper) {
    DotnetHelper = dotnetHelper;
    updatePosition();
}

var retry = 0;
function updatePosition() {
    DotnetHelper.invokeMethodAsync("IsPlaying").then(isPlaying => {
        DotnetHelper.invokeMethodAsync("UpdatePosition").then(() => { });

        if (isPlaying) {
            retry = 0;
            window.requestAnimationFrame(updatePosition);
        }
        else if (retry < 2) {
            retry++;
            window.requestAnimationFrame(updatePosition);
        }
        else retry = 0;
    })
}

Actually in fact the previous version of the code didn't have that issue... because it ran forever once it was called once due to me not yet understanding JS promises (can you tell I try to do as little JS as possible, thank Maui and the other Blazor gods that I don't need to do that much at all). When I fixed the code in the original solution I had the issue of it never calling itself recursively again due to the issue explained at the start of this comment.