| File: Internal\SapiInterop\EventNotify.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Speech.AudioFormat; using System.Threading; namespace System.Speech.Internal.SapiInterop { internal class SpNotifySink : ISpNotifySink { public SpNotifySink(EventNotify eventNotify) { _eventNotifyReference = new WeakReference(eventNotify); } void ISpNotifySink.Notify() { EventNotify? eventNotify = (EventNotify?)_eventNotifyReference.Target; if (eventNotify != null) { ThreadPool.QueueUserWorkItem(new WaitCallback(eventNotify.SendNotification)); } } private WeakReference _eventNotifyReference; } /// Dispatches events from ISpEventSource to DispatchEventDelegate on a thread /// compatible with the application model of the thread that created this object. internal class EventNotify { #region Constructors internal EventNotify(ISpEventSource sapiEventSource, IAsyncDispatch dispatcher, bool additionalSapiFeatures) { // Remember event source _sapiEventSourceReference = new WeakReference(sapiEventSource); _dispatcher = dispatcher; _additionalSapiFeatures = additionalSapiFeatures; // Start listening to events from sapiEventSource. _notifySink = new SpNotifySink(this); sapiEventSource.SetNotifySink(_notifySink); } #endregion Constructors #region Internal Methods // Finalizer is not required since ISpEventSource and AsyncOperation both implement appropriate finalizers. internal void Dispose() { lock (this) { // Since we are explicitly calling Dispose(), sapiEventSource (RCW) will normally be alive. // If Dispose() is called from a finalizer this may not be the case so check for null. if (_sapiEventSourceReference != null) { ISpEventSource? sapiEventSource = (ISpEventSource?)_sapiEventSourceReference.Target; if (sapiEventSource != null) { // Stop listening to events from sapiEventSource. sapiEventSource.SetNotifySink(null); _notifySink = null; } } _sapiEventSourceReference = null; } } internal void SendNotification(object? _) { lock (this) { // Call dispatchEventDelegate for each SAPI event currently queued. if (_sapiEventSourceReference != null) { ISpEventSource? sapiEventSource = (ISpEventSource?)_sapiEventSourceReference.Target; if (sapiEventSource != null) { List<SpeechEvent> speechEvents = new(); SpeechEvent? speechEvent; while (null != (speechEvent = SpeechEvent.TryCreateSpeechEvent(sapiEventSource, _additionalSapiFeatures, _audioFormat))) { speechEvents.Add(speechEvent); } _dispatcher.Post(speechEvents.ToArray()); } } } } #endregion Methods #region Internal Properties internal SpeechAudioFormatInfo? AudioFormat { set { _audioFormat = value; } } #endregion Methods #region Private Methods #endregion #region Private Fields private IAsyncDispatch _dispatcher; private WeakReference? _sapiEventSourceReference; private bool _additionalSapiFeatures; private SpeechAudioFormatInfo? _audioFormat; private ISpNotifySink? _notifySink; #endregion Private Fields } }