Skip to content

Instantly share code, notes, and snippets.

@marcominerva
Created July 3, 2026 08:38
Show Gist options
  • Select an option

  • Save marcominerva/0b201704be8d8da0d43b280632b9ebbf to your computer and use it in GitHub Desktop.

Select an option

Save marcominerva/0b201704be8d8da0d43b280632b9ebbf to your computer and use it in GitHub Desktop.
AudioRecorder.cs
using Microsoft.JSInterop;
namespace MeetingManager.Components.Services;
internal sealed class AudioRecorder(IJSRuntime jsRuntime, string modulePath = "./js/audio-recorder.js") : IAsyncDisposable
{
private readonly IJSRuntime jsRuntime = jsRuntime;
private IJSObjectReference module = null!;
public bool IsRecording { get; private set; }
public sealed record RecordedAudio(IJSStreamReference Stream, string MimeType);
public async ValueTask InitializeAsync()
{
if (module is not null)
{
return;
}
module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", modulePath);
}
public async Task StartAsync()
{
await EnsureModuleAsync();
try
{
await module.InvokeVoidAsync("startRecording");
IsRecording = true;
}
catch
{
IsRecording = false;
throw;
}
}
public async Task CancelAsync()
{
await EnsureModuleAsync();
try
{
await module.InvokeVoidAsync("cancelRecording");
}
finally
{
IsRecording = false;
}
}
public async Task<RecordedAudio> ConfirmAsync()
{
await EnsureModuleAsync();
try
{
var recordedAudio = await module.InvokeAsync<RecordedAudio>("confirmRecording");
return recordedAudio with
{
MimeType = string.IsNullOrWhiteSpace(recordedAudio.MimeType) ? "audio/webm" : recordedAudio.MimeType
};
}
finally
{
IsRecording = false;
}
}
private async ValueTask EnsureModuleAsync()
{
if (module is null)
{
await InitializeAsync();
}
}
public async ValueTask DisposeAsync()
{
if (module is null)
{
return;
}
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment