59 lines
1.8 KiB
C#
59 lines
1.8 KiB
C#
|
|
using System.Media;
|
||
|
|
|
||
|
|
namespace VoiceCat.App.Notifications;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Plays short event cues from the app's <c>sounds\</c> folder. Each WAV is loaded once into a
|
||
|
|
/// cached <see cref="SoundPlayer"/> (built into the Windows Desktop framework — no extra
|
||
|
|
/// dependency). <see cref="Play"/> is non-blocking (<see cref="SoundPlayer.Play"/> renders on a
|
||
|
|
/// background thread).
|
||
|
|
///
|
||
|
|
/// Note: <see cref="SoundPlayer"/> exposes no gain control, so volume is honoured only as a mute
|
||
|
|
/// gate (volume == 0 → silent). If finer control or reliable overlapping playback is needed
|
||
|
|
/// later, swap this for NAudio.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class SoundPlayerPool : IDisposable
|
||
|
|
{
|
||
|
|
private static readonly string SoundsDir =
|
||
|
|
Path.Combine(AppContext.BaseDirectory, "sounds");
|
||
|
|
|
||
|
|
private readonly Dictionary<SoundEvent, SoundPlayer?> _players = [];
|
||
|
|
|
||
|
|
/// <summary>Resolve, load and cache the player for an event. Returns null if the file is
|
||
|
|
/// missing or fails to load — playback then silently no-ops.</summary>
|
||
|
|
private SoundPlayer? Get(SoundEvent ev)
|
||
|
|
{
|
||
|
|
if (_players.TryGetValue(ev, out var cached)) return cached;
|
||
|
|
|
||
|
|
SoundPlayer? player = null;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
string path = Path.Combine(SoundsDir, ev.FileName());
|
||
|
|
if (File.Exists(path))
|
||
|
|
{
|
||
|
|
player = new SoundPlayer(path);
|
||
|
|
player.Load();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
player = null; // unreadable/invalid WAV — degrade to silence
|
||
|
|
}
|
||
|
|
|
||
|
|
_players[ev] = player;
|
||
|
|
return player;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Play(SoundEvent ev)
|
||
|
|
{
|
||
|
|
try { Get(ev)?.Play(); }
|
||
|
|
catch { /* never let a notification sound surface as an error */ }
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
foreach (var p in _players.Values) p?.Dispose();
|
||
|
|
_players.Clear();
|
||
|
|
}
|
||
|
|
}
|