Blazor 和 Superpowered Web Audio SDK,如何 return arrayBuffer 到 C#

Blazor and the Superpowered Web Audio SDK, how to return the arrayBuffer to C#

首先,对于这样一个悬而未决的问题,我们深表歉意。我认为这个问题来自于对 WASM 和 .Net 中 JSInterop 的本质缺乏理解。

我只是想联系任何在 Blazor 中使用过 Superpowered Web Audio SDK 的人,了解他们是如何使用它的,因为我正在为 JSInterop 苦苦挣扎,我觉得我没有让事情变得更难使用基于 Javascript 的框架。

我已经使用 C# class 设置了一个 Blazor 客户端 Web 程序集项目,它作为一个非常简单的 Javascript 文件的接口来下载和解码音频文件:

public class AudioTest
{
        [Inject]
        IJSRuntime js;

        DotNetObjectReference<AudioTest> objRef;

        protected override void OnInitialized()
        {
            objRef = DotNetObjectReference.Create(this);
        }

        public async void DownloadAndDecode(string url)
        {
            byte[] buffer = await superpoweredModule.InvokeAsync<byte[]>("downloadAndDecode", url, objRef);

            Console.WriteLine(buffer.Length);
        }
       
        [JSInvokable]
        public void ReceiveDecodedBuffer(string url, byte[] buffer)
        {
            Console.WriteLine(buffer);
        }
}

调用 C# 方法 DownloadAndDecode() 时,它将自身的引用传递给 javascript 函数 downloadAndDecode() 以在缓冲区准备就绪时用于回调:

import { SuperpoweredTrackLoader } from '/superpowered/SuperpoweredTrackLoaderModule.js';

export async function downloadAndDecode(url, dotNetRef) {
    SuperpoweredTrackLoader.downloadAndDecode(url, async (message) => {
        await dotNetRef.invokeMethodAsync('ReceiveDecodedBuffer', url, message.SuperpoweredLoaded.buffer);
    });
}

但是,这会导致在转换 base64 缓冲区时出现运行时错误。我试过在发送之前从 base64 转换音频缓冲区(这太慢了)。我还尝试了未编组的 Javascript 调用,但它们仅支持同步调用。在 C#、JS 之间传递时必须转换缓冲区,反之亦然。

我计划在 C# 和 JS 上处理音频缓冲区。但感觉我应该离开 JS 端并在那里管理缓冲区。有人对此有建议吗?或者我应该把它留在 Javascript 一边吗?或者简单地更改我的 design/approach 和框架以支持 Superpowered 库。

安装 .net 6 preview 6 并再次创建我的项目提供了一种在 Blazor 和 JavaScript 之间传递大字节 [] 的快速有效方法。在不创建新项目的情况下,当 returning/sending byte[] .

时会导致奇怪的行为

这是我的源代码示例。该代码需要 Superpowered Web Audio 库。 ByteArrayTest.razor

<h3>ByteArrayTest</h3>

<button @onclick="SendNetBytes">Send bytes to javascript</button>
<button @onclick="GetJavaBytes">Get bytes from javascript</button>
<button @onclick="DownloadAndDecode">Download And Decode .mp3</button>
<button @onclick="DownloadAndDecodeUsingCallback">Download And Decode .mp3 Using Callback</button>

@code {
    [Inject]
    IJSRuntime jsRuntime { get; set; }
    IJSObjectReference module;
    DotNetObjectReference<ByteArrayTest> objRef;

    protected override async Task OnInitializedAsync()
    {
        objRef = DotNetObjectReference.Create(this);
        module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/byteArray.js");
    }

    public async ValueTask DisposeAsync()
    {
        objRef.Dispose();
        await module.DisposeAsync();
    }

    public async void SendNetBytes()
    {
        byte[] bytes = new byte[] { 1, 5, 7 };
        await module.InvokeVoidAsync("getNetBytes", bytes);
    }

    public async void GetJavaBytes()
    {
        byte[] buffer = await module.InvokeAsync<byte[]>("getJavaBytes");
        Console.WriteLine(buffer.Length);
        foreach (byte b in buffer)
        {
            Console.WriteLine(b);
        }
    }

    public async void DownloadAndDecode()
    {
        byte[] buffer = await module.InvokeAsync<byte[]>("downloadAndDecode", "/track.mp3");
        Console.WriteLine(buffer.Length);
        await module.InvokeVoidAsync("getNetBytes", buffer);
    }

    public async void DownloadAndDecodeUsingCallback()
    {
        await module.InvokeVoidAsync("downloadAndDecodeUsingCallback", "/track.mp3", objRef);
    }

    [JSInvokable]
    public async void ReceiveDecodedBuffer(byte[] buffer)
    {
        Console.WriteLine("Got buffer!");
        Console.WriteLine(buffer.Length);
        await module.InvokeVoidAsync("getNetBytes", buffer);
    }
}

wwwroot/byteArray.js

export function getNetBytes(bytes) {
    console.log(bytes);
}

export function getJavaBytes() {
    return new Uint8Array([1, 2, 3, 4, 5]);
}

import { SuperpoweredTrackLoader } from '/superpowered/SuperpoweredTrackLoaderModule.js';

export async function downloadAndDecode(url) {
    const promise = new Promise((resolve) => {
        SuperpoweredTrackLoader.downloadAndDecode(url, async (message) => {
            const buffer = new Uint8Array(message.SuperpoweredLoaded.buffer);
            resolve(buffer);
        });
    });

    const buffer = await promise;
    return buffer;
}

export function downloadAndDecodeUsingCallback(url, dotNetRef) {
    SuperpoweredTrackLoader.downloadAndDecode(url, async (message) => {
        const buffer = new Uint8Array(message.SuperpoweredLoaded.buffer);
        await dotNetRef.invokeMethodAsync('ReceiveDecodedBuffer', buffer);
    });
}