feat(clients): event sound effects + optional text-to-speech
Add audible cues and optional spoken announcements for session events (join/leave, channel + PM sent/recv, login, logout/connection-lost, mic on/off, voice-activity, PTT) across all three clients, driven off the shared C ABI vc_event stream so the mapping stays consistent. TTS is off by default; when enabled it announces events and reads message/PM bodies aloud. Master toggles + a sound-volume slider; the per-utterance voice-activity and PTT cues default off. WAVs ship from assets/sounds/. Windows (built + verified): new VoiceCat.App/Notifications/ layer (FeedbackSettings -> %AppData%\VoiceCat\feedback.json, SoundPlayerPool via System.Media.SoundPlayer, SpeechAnnouncer via Prismatoid 0.3.0, EventFeedback dispatcher); MainForm hooks; NotificationSettingsForm under Settings > Notifications; csproj adds the Prismatoid PackageRef and copies the WAVs into sounds\. macOS + iOS (written, not yet built -- needs a Mac): shared VoiceCatCore/Feedback/ (SoundEvent, EventFeedback = AVAudioPlayer pool + native AVSpeechSynthesizer, FeedbackSettings over UserDefaults); WAVs bundled via Package.swift resources (.process). Hooks in SessionState/ AppState (iOS) and MainWindowController (macOS); settings UI in SettingsView (iOS) and SettingsWindowController (macOS). No core/server code touched; ctest --preset dev unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace VoiceCat.App.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// User preferences for event sounds and spoken (text-to-speech) feedback. Persisted to
|
||||
/// %AppData%\VoiceCat\feedback.json — same pattern as <see cref="Models.ServerListStore"/>:
|
||||
/// a missing or corrupt file yields defaults rather than throwing.
|
||||
/// </summary>
|
||||
public sealed class FeedbackSettings
|
||||
{
|
||||
/// <summary>Master switch for event sound effects.</summary>
|
||||
public bool Sounds { get; set; } = true;
|
||||
|
||||
/// <summary>Master switch for spoken announcements (Prismatoid TTS). Off by default.</summary>
|
||||
public bool Speech { get; set; } = false;
|
||||
|
||||
/// <summary>Sound-effects volume, 0..1. 0 mutes effects (SoundPlayer has no gain control,
|
||||
/// so this is honoured as a mute gate — see <see cref="SoundPlayerPool"/>).</summary>
|
||||
public float Volume { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>Play va_start/va_stop for your own voice-activity transitions. Off by default
|
||||
/// (fires on every utterance — noisy).</summary>
|
||||
public bool SelfTalkSounds { get; set; } = false;
|
||||
|
||||
/// <summary>Play the ptt cue when push-to-talk is engaged. Off by default.</summary>
|
||||
public bool PttSound { get; set; } = false;
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
||||
|
||||
private static string AppDataDir => Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VoiceCat");
|
||||
|
||||
private static string FilePath => Path.Combine(AppDataDir, "feedback.json");
|
||||
|
||||
public static FeedbackSettings Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(FilePath)) return new FeedbackSettings();
|
||||
string json = File.ReadAllText(FilePath);
|
||||
return JsonSerializer.Deserialize<FeedbackSettings>(json) ?? new FeedbackSettings();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new FeedbackSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Directory.CreateDirectory(AppDataDir);
|
||||
File.WriteAllText(FilePath, JsonSerializer.Serialize(this, JsonOptions));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user