Reputation: 31
First of all, apologies for such an open question. I think this question comes from a lack of understanding of WASM and the nature of JSInterop in .Net.
I just wanted to reach out to anyone who has used the Superpowered Web Audio SDK with Blazor and find out how they have used it as I am struggling with JSInterop, and I feel like I am making things harder by not using a Javascript based framework.
I've setup a Blazor client web assembly project with a C# class, which acts as an interface to a very simple Javascript file to download and decode an audio file:
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);
}
}
When the C# method DownloadAndDecode() has been called, it passes a reference of itself to the javascript function downloadAndDecode() to be used a call back when the buffer is ready:
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);
});
}
However, this results in a runtime error when converting the base64 buffer. I've tried converting the audio buffer from base64 before sending it (which is too slow). I also tried unmarshalled Javascript calls but they only support synchronous calls. Having to convert the buffer when passing between C#, JS and vice versa is too slow.
I planned on processing the audio buffer on both C# and JS. But it feels like I should just leave JS side and manage the buffers there. Does anyone have a suggestion for this? Or should I just leave it in the Javascript side? Or simply change my design/approach and framework to support the Superpowered library.
Upvotes: 1
Views: 815
Reputation: 31
Installing .net 6 preview 6 and creating my project again provided a fast and effective way of passing large byte[] between Blazor and JavaScript. Without creating a new project it caused odd behaviour when returning/sending the byte[] .
Here's a sample of my source code. The code requires the Superpowered Web Audio library. 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);
});
}
Upvotes: 2