2
0
mirror of https://github.com/9ParsonsB/Pulsar.git synced 2025-04-05 17:39:39 -04:00
Xjph 554948534e
observatory herald (#30)
* WIP: initial commit for observatory herald

* Plugin error handling refactor

* make error window non-modal

* tidy up plugin error handling

* first pass for basic herald functionality

* corrections for linux env

* Use FNV hash directly instead of managing through dictionary/index file

* resolve audio queuing issue, switch to personal NetCoreAudio fork

* merge cleanup

* add enable setting, populate defaults

* framework xml doc update

* Adjust settings, add style selection, replace locale with demonym in dropdown list.

* Test is position is on screen before saving/loading.

* use a default that's actually in the list
2021-11-15 10:57:46 -03:30

97 lines
2.8 KiB
C#

using Observatory.Framework;
using System.Collections.Generic;
using System.Xml;
using System.Linq;
using System.Threading.Tasks;
using System.Speech.Synthesis;
using System.Runtime.InteropServices;
namespace Observatory.NativeNotification
{
public class NativeVoice
{
private Queue<NotificationArgs> notificationEvents;
private bool processing;
public NativeVoice()
{
notificationEvents = new();
processing = false;
}
public void EnqueueAndAnnounce(NotificationArgs eventArgs)
{
notificationEvents.Enqueue(eventArgs);
if (!processing)
{
processing = true;
ProcessQueueAsync();
}
}
private async void ProcessQueueAsync()
{
await Task.Factory.StartNew(ProcessQueue);
}
private void ProcessQueue()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
string voice = Properties.Core.Default.VoiceSelected;
var speech = new SpeechSynthesizer()
{
Volume = Properties.Core.Default.VoiceVolume,
Rate = Properties.Core.Default.VoiceRate
};
speech.SelectVoice(voice);
while (notificationEvents.Any())
{
var notification = notificationEvents.Dequeue();
if (notification.TitleSsml?.Length > 0)
{
string ssml = AddVoiceToSsml(notification.TitleSsml, voice);
speech.SpeakSsml(ssml);
}
else
{
speech.Speak(notification.Title);
}
if (notification.DetailSsml?.Length > 0)
{
string ssml = AddVoiceToSsml(notification.DetailSsml, voice);
speech.SpeakSsml(ssml);
}
else
{
speech.Speak(notification.Detail);
}
}
}
processing = false;
}
private string AddVoiceToSsml(string ssml, string voiceName)
{
XmlDocument ssmlDoc = new();
ssmlDoc.LoadXml(ssml);
var ssmlNamespace = ssmlDoc.DocumentElement.NamespaceURI;
XmlNamespaceManager ssmlNs = new(ssmlDoc.NameTable);
ssmlNs.AddNamespace("ssml", ssmlNamespace);
var voiceNode = ssmlDoc.SelectSingleNode("/ssml:speak/ssml:voice", ssmlNs);
voiceNode.Attributes.GetNamedItem("name").Value = voiceName;
return ssmlDoc.OuterXml;
}
}
}