AUdio Player Service refactor

This commit is contained in:
daniel-c-harvey
2025-09-08 14:20:38 -04:00
parent bf054f3d1b
commit a25d067dff
14 changed files with 323 additions and 158 deletions
@@ -10,19 +10,25 @@
@if (IsLoaded)
{
<MudIconButton Icon="Icons.Material.Filled.Stop"
Color="Color.Secondary"
Color="Color.Primary"
OnClick="@Stop"
Disabled="!IsLoaded"/>
}
</MudStack>
<MudText Typo="Typo.body2" Class="font-monospace deepdrft-audio-time">
@FormatTime(CurrentTime) / @FormatTime(Duration)
</MudText>
<MudStack Row AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="font-monospace deepdrft-audio-time">
@FormatTime(CurrentTime) / @(Duration.HasValue ? FormatTime(Duration.Value) : "--:--")
</MudText>
@if (!IsLoaded)
{
<MudProgressCircular Color="Color.Tertiary" Value="@LoadProgress" Size="Size.Small"/>
}
</MudStack>
</MudStack>
<MudSlider T="double"
Min="0"
Max="@Duration"
Max="@(Duration ?? 0D)"
Step="0.1"
Value="@CurrentTime"
ValueChanged="@OnSeek"
@@ -6,27 +6,25 @@ using MudBlazor;
namespace DeepDrftWeb.Client.Controls;
public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
public partial class AudioPlayerBar : ComponentBase
{
[CascadingParameter] public required IPlayerService PlayerService { get; set; }
[Parameter] public bool ShowLoadProgress { get; set; } = true;
[Parameter] public required AudioPlaybackEngine AudioPlaybackEngine { get; set; }
private bool IsLoaded => AudioPlaybackEngine.IsLoaded;
private bool IsPlaying => AudioPlaybackEngine.IsPlaying;
private bool IsPaused => AudioPlaybackEngine.IsPaused;
private double CurrentTime => AudioPlaybackEngine.CurrentTime;
private double Duration => AudioPlaybackEngine.Duration;
private double Volume => AudioPlaybackEngine.Volume;
private double LoadProgress => AudioPlaybackEngine.LoadProgress;
private string? ErrorMessage => AudioPlaybackEngine.ErrorMessage;
private bool IsLoaded => PlayerService.IsLoaded;
private bool IsPlaying => PlayerService.IsPlaying;
private bool IsPaused => PlayerService.IsPaused;
private double CurrentTime => PlayerService.CurrentTime;
private double? Duration => PlayerService.Duration;
private double Volume => PlayerService.Volume;
private double LoadProgress => PlayerService.LoadProgress;
private string? ErrorMessage => PlayerService.ErrorMessage;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
AudioPlaybackEngine.OnProgressChanged += async _ => StateHasChanged();
AudioPlaybackEngine.OnPlaybackEnded += async () => await Stop(); // TODO unload the engine track instead of stopping
PlayerService.OnStateChanged += StateHasChanged;
}
private string GetPlayIcon()
@@ -49,36 +47,27 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
private async Task TogglePlayPause()
{
await AudioPlaybackEngine.TogglePlayPause();
StateHasChanged();
await PlayerService.TogglePlayPause();
}
private async Task Stop()
{
await AudioPlaybackEngine.Stop();
StateHasChanged();
await PlayerService.Stop();
}
private async Task OnSeek(double position)
{
await AudioPlaybackEngine.OnSeek(position);
StateHasChanged();
await PlayerService.Seek(position);
}
private async Task OnVolumeChange(double volume)
{
await AudioPlaybackEngine.OnVolumeChange(volume);
StateHasChanged();
await PlayerService.SetVolume(volume);
}
private void ClearError()
{
AudioPlaybackEngine.ClearError();
StateHasChanged();
PlayerService.ClearError();
}
public async ValueTask DisposeAsync()
{
await AudioPlaybackEngine.DisposeAsync();
}
}
@@ -0,0 +1,5 @@
@using DeepDrftWeb.Client.Services
<CascadingValue Value="@(PlayerService)" IsFixed="true">
@ChildContent
</CascadingValue>
@@ -0,0 +1,33 @@
using DeepDrftWeb.Client.Services;
using Microsoft.AspNetCore.Components;
using DeepDrftModels.Entities;
namespace DeepDrftWeb.Client.Controls;
public partial class AudioPlayerService : ComponentBase
{
[Inject] public required AudioPlaybackEngine AudioPlaybackEngine { get; set; }
private readonly PlayerService _playerService = new();
private IPlayerService PlayerService => _playerService;
[Parameter] public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
// PlayerService is already created as a field, so it's immediately available to cascading components
// It will be in uninitialized state until OnAfterRenderAsync when AudioPlaybackEngine is ready
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Initialize the PlayerService with the AudioPlaybackEngine now that it's available
await _playerService.InitializeAsync(AudioPlaybackEngine);
StateHasChanged();
}
}
}