using AVFoundation; using Foundation; namespace VoiceCat.Mac; internal enum SoundEvent { ChannelJoin, ChannelLeave, ChannelReceived, ChannelSent, PrivateReceived, PrivateSent, Login, Logout, ConnectionLost, VoiceOn, VoiceOff, VoiceStart, VoiceStop, PushToTalk } internal sealed class EventFeedback : IDisposable { private readonly MacSettings settings; private readonly AVSpeechSynthesizer speech = new(); private readonly Dictionary players = []; internal EventFeedback(MacSettings settings) => this.settings = settings; internal void Play(SoundEvent sound) { if (!settings.EventSounds || settings.EventVolume <= 0 || (sound is SoundEvent.VoiceStart or SoundEvent.VoiceStop && !settings.SelfTalkSounds) || (sound == SoundEvent.PushToTalk && !settings.PushToTalkSound)) return; if (!players.TryGetValue(sound, out AVAudioPlayer? player)) { string path = Path.Combine(NSBundle.MainBundle.ResourcePath ?? "", "Sounds", FileName(sound) + ".wav"); if (!File.Exists(path)) return; player = AVAudioPlayer.FromUrl(NSUrl.FromFilename(path)); if (player is null) return; player.PrepareToPlay(); players[sound] = player; } player.Volume = settings.EventVolume; player.CurrentTime = 0; player.Play(); } internal void Speak(string text) { if (!settings.SpokenEvents || string.IsNullOrWhiteSpace(text)) return; speech.SpeakUtterance(new AVSpeechUtterance(text.Trim())); } private static string FileName(SoundEvent value) => value switch { SoundEvent.ChannelJoin => "channel_join", SoundEvent.ChannelLeave => "channel_leave", SoundEvent.ChannelReceived => "channel_recv", SoundEvent.ChannelSent => "channel_sent", SoundEvent.PrivateReceived => "pm_recv", SoundEvent.PrivateSent => "pm_sent", SoundEvent.Login => "login", SoundEvent.Logout => "logout", SoundEvent.ConnectionLost => "connection_lost", SoundEvent.VoiceOn => "voice_on", SoundEvent.VoiceOff => "voice_off", SoundEvent.VoiceStart => "va_start", SoundEvent.VoiceStop => "va_stop", _ => "ptt" }; public void Dispose() { foreach (AVAudioPlayer player in players.Values) player.Dispose(); speech.Dispose(); } }