mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-06 07:36:01 +02:00
Merge pull request #36 from HueByte/dev_fix_notification_sound
fix: error when playing notification sounds in quick succession
This commit is contained in:
@@ -13,6 +13,7 @@ Follow-up patch release for v0.2.9 addressing auto-updater regressions, adding a
|
|||||||
- Fix pre-update backup failing when a Serilog-held log file is locked — `UpdateBackupService` now enumerates files manually, skips the `logs/` directory and `.log` files, and logs-and-continues on `IOException`/`UnauthorizedAccessException` instead of aborting the whole backup
|
- Fix pre-update backup failing when a Serilog-held log file is locked — `UpdateBackupService` now enumerates files manually, skips the `logs/` directory and `.log` files, and logs-and-continues on `IOException`/`UnauthorizedAccessException` instead of aborting the whole backup
|
||||||
- Simplify update progress dispatch — remove redundant `Application.Invoke` wrappers around progress updates that are already called from the UI thread (introduced while fixing the freeze above)
|
- Simplify update progress dispatch — remove redundant `Application.Invoke` wrappers around progress updates that are already called from the UI thread (introduced while fixing the freeze above)
|
||||||
- Fix cursor position being reset to the start of the line when auto-completing commands in the CLI app — insertion point is now moved to the end of the completed text
|
- Fix cursor position being reset to the start of the line when auto-completing commands in the CLI app — insertion point is now moved to the end of the completed text
|
||||||
|
- Fix notification sounds crashing or being silently dropped when several arrive in quick succession — playback is now serialized through a semaphore that's held for the duration of each sound (using `PlaybackFinished` with a 10s safety timeout) and always released in `finally`, so back-to-back notifications queue up and play in order instead of racing the underlying audio player (fixes #20)
|
||||||
|
|
||||||
## Refactoring
|
## Refactoring
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ namespace EchoHub.Client.Services;
|
|||||||
|
|
||||||
public class NotificationSoundService
|
public class NotificationSoundService
|
||||||
{
|
{
|
||||||
|
// Safety net: if PlaybackFinished never fires we don't want to block future notifications forever.
|
||||||
|
private static readonly TimeSpan PlaybackTimeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
private readonly Player _player = new();
|
private readonly Player _player = new();
|
||||||
|
private readonly SemaphoreSlim _lock = new(1, 1);
|
||||||
private readonly NotificationConfig _config;
|
private readonly NotificationConfig _config;
|
||||||
private string? _resolvedSoundPath;
|
private string? _resolvedSoundPath;
|
||||||
|
|
||||||
@@ -41,18 +45,31 @@ public class NotificationSoundService
|
|||||||
|
|
||||||
private async Task PlayInternal()
|
private async Task PlayInternal()
|
||||||
{
|
{
|
||||||
|
await _lock.WaitAsync();
|
||||||
|
|
||||||
|
// _player.Play returns as soon as playback starts, so we wait on PlaybackFinished
|
||||||
|
// to hold the lock for the duration of the sound. A one-shot handler + timeout
|
||||||
|
// keeps the finally release robust: never-fires → timeout; fires twice → ignored
|
||||||
|
// (TrySetResult); handler throws → caller's catch still runs finally.
|
||||||
|
var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
void OnFinished(object? s, EventArgs e) => completion.TrySetResult();
|
||||||
|
_player.PlaybackFinished += OnFinished;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_player.Playing)
|
|
||||||
await _player.Stop();
|
|
||||||
|
|
||||||
await _player.SetVolume(_config.Volume);
|
await _player.SetVolume(_config.Volume);
|
||||||
await _player.Play(_resolvedSoundPath!);
|
await _player.Play(_resolvedSoundPath!);
|
||||||
|
await Task.WhenAny(completion.Task, Task.Delay(PlaybackTimeout));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warning(ex, "Failed to play notification sound");
|
Log.Warning(ex, "Failed to play notification sound");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_player.PlaybackFinished -= OnFinished;
|
||||||
|
_lock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResolveSoundPath()
|
private void ResolveSoundPath()
|
||||||
|
|||||||
Reference in New Issue
Block a user