using Microsoft.JSInterop; namespace DeepDrftWeb.Client.Services; public class AudioInteropService : IAsyncDisposable { private readonly IJSRuntime _jsRuntime; private readonly Dictionary> _callbacks = new(); public AudioInteropService(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime; } public async Task CreatePlayerAsync(string playerId) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.createPlayer", playerId); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task LoadAudioFromUrlAsync(string playerId, string url) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.loadAudioFromUrl", playerId, url); return result; } catch (Exception ex) { return new AudioLoadResult { Success = false, Error = ex.Message }; } } public async Task PlayAsync(string playerId) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.play", playerId); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task PauseAsync(string playerId) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.pause", playerId); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task StopAsync(string playerId) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.stop", playerId); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task SeekAsync(string playerId, double position) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.seek", playerId, position); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task SetVolumeAsync(string playerId, double volume) { try { var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.setVolume", playerId, volume); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task GetCurrentTimeAsync(string playerId) { try { return await _jsRuntime.InvokeAsync("DeepDrftAudio.getCurrentTime", playerId); } catch (Exception) { return 0; } } public async Task GetStateAsync(string playerId) { try { return await _jsRuntime.InvokeAsync("DeepDrftAudio.getState", playerId); } catch (Exception) { return null; } } public async Task SetOnProgressCallbackAsync(string playerId, Func callback) { try { var callbackWrapper = new AudioPlayerCallback(); callbackWrapper.OnProgress = callback; var dotNetObjectRef = DotNetObjectReference.Create(callbackWrapper); _callbacks[playerId + "_progress"] = dotNetObjectRef; var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.setOnProgressCallback", playerId, dotNetObjectRef, "OnProgressCallback"); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task SetOnEndCallbackAsync(string playerId, Func callback) { try { var callbackWrapper = new AudioPlayerCallback(); callbackWrapper.OnEnd = callback; var dotNetObjectRef = DotNetObjectReference.Create(callbackWrapper); _callbacks[playerId + "_end"] = dotNetObjectRef; var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.setOnEndCallback", playerId, dotNetObjectRef, "OnEndCallback"); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task SetOnLoadProgressCallbackAsync(string playerId, Func callback) { try { var callbackWrapper = new AudioPlayerCallback(); callbackWrapper.OnLoadProgress = callback; var dotNetObjectRef = DotNetObjectReference.Create(callbackWrapper); _callbacks[playerId + "_loadprogress"] = dotNetObjectRef; var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.setOnLoadProgressCallback", playerId, dotNetObjectRef, "OnLoadProgressCallback"); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async Task DisposePlayerAsync(string playerId) { try { // Clean up callbacks var keysToRemove = _callbacks.Keys.Where(k => k.StartsWith(playerId + "_")).ToList(); foreach (var key in keysToRemove) { _callbacks[key]?.Dispose(); _callbacks.Remove(key); } var result = await _jsRuntime.InvokeAsync("DeepDrftAudio.disposePlayer", playerId); return result; } catch (Exception ex) { return new AudioOperationResult { Success = false, Error = ex.Message }; } } public async ValueTask DisposeAsync() { foreach (var callback in _callbacks.Values) { callback?.Dispose(); } _callbacks.Clear(); } } public class AudioPlayerCallback { public Func? OnProgress { get; set; } public Func? OnEnd { get; set; } public Func? OnLoadProgress { get; set; } [JSInvokable] public async Task OnProgressCallback(double currentTime) { if (OnProgress != null) await OnProgress(currentTime); } [JSInvokable] public async Task OnEndCallback() { if (OnEnd != null) await OnEnd(); } [JSInvokable] public async Task OnLoadProgressCallback(double progress) { if (OnLoadProgress != null) await OnLoadProgress(progress); } } public class AudioOperationResult { public bool Success { get; set; } public string? Error { get; set; } } public class AudioLoadResult : AudioOperationResult { public double Duration { get; set; } public int SampleRate { get; set; } public int NumberOfChannels { get; set; } public double LoadProgress { get; set; } } public class AudioPlayerState { public bool IsPlaying { get; set; } public bool IsPaused { get; set; } public double CurrentTime { get; set; } public double Duration { get; set; } public double Volume { get; set; } public double LoadProgress { get; set; } }