Decompiled source of BoomboxTTS v1.0.1

BoomboxMod.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BoomboxMod.Voice;
using GameNetcodeStuff;
using HarmonyLib;
using LethalNetworkAPI;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BoomboxMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BoomboxMod")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a4a64f24-92c8-43f6-a94e-b511157c3b05")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BoomboxMod
{
	public class BoomboxClient
	{
		public static readonly int OutBufferSize = 8192;

		public static readonly int InBufferSize = 8388608;

		private readonly NamedPipeClientStream clientStream;

		private readonly StreamWriter streamWriter;

		private readonly BinaryReader binaryReader;

		public float[] buffer = new float[InBufferSize];

		public byte[] audioByteBuffer = new byte[InBufferSize * 2];

		public float audioLengthSeconds = 0f;

		public bool connected = false;

		public BoomboxClient()
		{
			try
			{
				clientStream = new NamedPipeClientStream("BOOMBOX");
				streamWriter = new StreamWriter(clientStream, Encoding.UTF8, OutBufferSize, leaveOpen: true);
				binaryReader = new BinaryReader(clientStream, Encoding.UTF8, leaveOpen: true);
			}
			catch (IOException data)
			{
				BoomboxPlugin.Error(data);
			}
		}

		public void Initialize()
		{
			CreateServer();
			ConnectToServer();
			connected = true;
		}

		private void CreateServer()
		{
			Process[] processesByName = Process.GetProcessesByName("BoomboxSynthesizer");
			Process[] array = processesByName;
			foreach (Process process in array)
			{
				process.Close();
			}
			string baseDirectory = BoomboxPlugin.GetBaseDirectory();
			Process process2 = Process.Start(baseDirectory + "BoomboxSynthesizer.exe");
			if (process2 == null)
			{
				BoomboxPlugin.Error("Failed to start BoomboxSynthesizer.");
			}
			else
			{
				BoomboxPlugin.Log("Started BoomboxSynthesizer");
			}
		}

		public string FilterMessageContent(string input)
		{
			return input.Replace("\r", "").Replace("\n", "").Replace("_", " ");
		}

		private void ConnectToServer()
		{
			BoomboxPlugin.Log("Connecting to server...");
			try
			{
				clientStream.Connect(7500);
			}
			catch (TimeoutException arg)
			{
				BoomboxPlugin.Error($"Connection timed out: {arg}");
			}
			catch (IOException arg2)
			{
				BoomboxPlugin.Error($"Failed to connect to server: {arg2}");
			}
		}

		public MessageData Speak(int playerId, string content, string voice, float volumeScale = 1f)
		{
			if (!connected)
			{
				BoomboxPlugin.Error("Tried to speak before connection established!");
				return default(MessageData);
			}
			SendMessageToServer(FilterMessageContent(content), voice);
			ClearSamplesBuffer();
			int num = binaryReader.ReadInt32();
			if (num > audioByteBuffer.Length)
			{
				audioByteBuffer = new byte[num];
			}
			Array.Clear(buffer, 0, num);
			int num2 = 0;
			binaryReader.Read(audioByteBuffer, 0, num);
			for (int i = 0; i < Math.Min(num / 2, buffer.Length); i++)
			{
				float num3 = volumeScale * ((float)BitConverter.ToInt16(audioByteBuffer, i * 2) / 32767f);
				buffer[i] = num3;
				if (num3 != 0f)
				{
					num2 = i;
				}
			}
			float lengthSeconds = (float)num2 / 11025f;
			BoomboxPlugin.Log("Completed: " + content);
			return new MessageData(playerId, buffer, lengthSeconds);
		}

		private void SendMessageToServer(string content, string voice)
		{
			BoomboxPlugin.Log("Sending to server: " + content);
			if (!clientStream.IsConnected)
			{
				CreateServer();
				ConnectToServer();
			}
			try
			{
				streamWriter.WriteLine(voice + "=" + content);
				streamWriter.Flush();
			}
			catch (Exception data)
			{
				BoomboxPlugin.Error(data);
			}
		}

		private void ClearSamplesBuffer()
		{
			for (int i = 0; i < buffer.Length; i++)
			{
				buffer[i] = 0f;
			}
		}
	}
	[BepInPlugin("ExDrill.BoomboxMod", "BoomboxMod", "1.0.0")]
	public class BoomboxPlugin : BaseUnityPlugin
	{
		public const string ModGUID = "ExDrill.BoomboxMod";

		public const string ModName = "BoomboxMod";

		public const string ModVersion = "1.0.0";

		public static BoomboxClient Client;

		public static bool IsNiceChatLoaded;

		public readonly Harmony harmony = new Harmony("ExDrill.BoomboxMod");

		protected static ManualLogSource logger;

		public void Awake()
		{
			logger = ((BaseUnityPlugin)this).Logger;
			Client = new BoomboxClient();
			IsNiceChatLoaded = false;
			Client.Initialize();
			BoomboxConfig.Initialize(((BaseUnityPlugin)this).Config);
			harmony.PatchAll();
		}

		public void OnDestroy()
		{
			if (Harmony.HasAnyPatches("taffyko.NiceChat"))
			{
				Log("Nice Chat detected.");
				IsNiceChatLoaded = true;
			}
		}

		public static void Log(object data)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo(data);
			}
		}

		public static void Warn(object data)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogWarning(data);
			}
		}

		public static void Error(object data)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogError(data);
			}
		}

		public static string GetBaseDirectory()
		{
			return new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath.Replace("BoomboxMod.dll", "");
		}
	}
	public class BoomboxConfig
	{
		public static ConfigEntry<float> Volume;

		public static ConfigEntry<string> SilencePrefix;

		private static bool isLoaded;

		public static void Initialize(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (!isLoaded)
			{
				Volume = config.Bind<float>("Tweaks", "TTS Volume", 0.5f, (ConfigDescription)null);
				SilencePrefix = config.Bind<string>("Tweaks", "Silence Prefix", "/", new ConfigDescription("TTS by default will be silenced if a message was sent with the / prefix, this can be changed.", (AcceptableValueBase)null, Array.Empty<object>()));
				isLoaded = true;
			}
		}
	}
	[HarmonyPatch]
	public class Patches
	{
		private static string lastSentMessage = "";

		[PublicNetworkVariable]
		public static LethalNetworkVariable<Dictionary<string, string>> UserToVoice = new LethalNetworkVariable<Dictionary<string, string>>("boomboxUserToVoice")
		{
			Value = new Dictionary<string, string>()
		};

		private static float[] emptyBuffer = new float[BoomboxClient.InBufferSize];

		private static readonly List<Message> Queue = new List<Message>();

		private static Task<MessageData> currentTask = null;

		[HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageClientRpc")]
		[HarmonyPostfix]
		public static void AddPlayerChatMessageClientRpcPostfix(HUDManager __instance, string chatMessage, int playerId)
		{
			PlayerControllerB[] players = GetPlayers();
			if (playerId > players.Length || (Object)(object)players[playerId] == (Object)null)
			{
				return;
			}
			PlayerControllerB val = players[playerId];
			if (VoiceChanged(val, chatMessage))
			{
				return;
			}
			BoomboxPlugin.Log(val.playerUsername);
			if (!UserToVoice.Value.ContainsKey(val.playerUsername))
			{
				UserToVoice.Value[val.playerUsername] = "none";
			}
			if (UserToVoice.Value[val.playerUsername] == "none")
			{
				return;
			}
			if (!BoomboxPlugin.IsNiceChatLoaded)
			{
				if (lastSentMessage == chatMessage)
				{
					return;
				}
				lastSentMessage = chatMessage;
			}
			if (!chatMessage.StartsWith(BoomboxConfig.SilencePrefix.Value))
			{
				Queue.Add(new Message(playerId, chatMessage));
			}
		}

		[HarmonyPatch(typeof(HUDManager), "Update")]
		[HarmonyPostfix]
		public static void UpdatePostfix(HUDManager __instance)
		{
			if (currentTask != null)
			{
				if (!currentTask.IsCompleted)
				{
					return;
				}
				if (!currentTask.IsCanceled && !currentTask.IsFaulted)
				{
					Speak(__instance.playersManager, currentTask.Result);
				}
				currentTask = null;
			}
			if (Queue.Count > 0)
			{
				Message next = Queue[0];
				PlayerControllerB player = __instance.playersManager.allPlayerScripts[next.playerId];
				Queue.RemoveAt(0);
				currentTask = Task.Run(() => BoomboxPlugin.Client.Speak(next.playerId, next.content, UserToVoice.Value[player.playerUsername]));
			}
		}

		public static void Speak(StartOfRound playerManager, MessageData data)
		{
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = playerManager.allPlayerScripts[data.playerId];
			if ((Object)(object)val == (Object)null)
			{
				BoomboxPlugin.Warn("Couldn't find player");
				return;
			}
			BoomboxPlugin.Log("Found player");
			GameObject orCreateSpeaker = GetOrCreateSpeaker(val);
			AudioSource component = orCreateSpeaker.GetComponent<AudioSource>();
			if ((Object)(object)component == (Object)null)
			{
				BoomboxPlugin.Error("Failed to speak, audio source not found!");
				return;
			}
			if ((Object)(object)component.clip == (Object)null)
			{
				component.clip = AudioClip.Create("BOOMBOX_CLIP", BoomboxClient.InBufferSize, 1, 11025, false);
			}
			BoomboxPlugin.Log("Adding sample to clip.");
			component.clip.SetData(emptyBuffer, 0);
			component.clip.SetData(data.buffer, 0);
			if (!((Object)(object)SoundManager.Instance.playerVoiceMixers[val.playerClientId] == (Object)null))
			{
				component.outputAudioMixerGroup = SoundManager.Instance.playerVoiceMixers[val.playerClientId];
				component.playOnAwake = false;
				component.rolloffMode = (AudioRolloffMode)2;
				component.minDistance = 1f;
				component.maxDistance = 40f;
				component.dopplerLevel = 0.5f;
				component.pitch = 1f;
				component.spatialize = true;
				component.spatialBlend = (val.isPlayerDead ? 0f : 1f);
				bool flag = !val.isPlayerDead || StartOfRound.Instance.localPlayerController.isPlayerDead;
				component.volume = (flag ? BoomboxConfig.Volume.Value : 0f);
				BoomboxPlugin.Log("Adjusted audio source");
				AudioHighPassFilter component2 = orCreateSpeaker.GetComponent<AudioHighPassFilter>();
				if ((Object)(object)component2 != (Object)null)
				{
					((Behaviour)component2).enabled = false;
				}
				AudioLowPassFilter component3 = orCreateSpeaker.GetComponent<AudioLowPassFilter>();
				if ((Object)(object)component3 != (Object)null)
				{
					component3.lowpassResonanceQ = 1f;
					component3.cutoffFrequency = 5000f;
				}
				BoomboxPlugin.Log("Adjusted audio filters");
				if (component.isPlaying)
				{
					component.Stop();
				}
				component.PlayOneShot(component.clip, 1f);
				RoundManager.Instance.PlayAudibleNoise(orCreateSpeaker.transform.position, 25f, 0.7f, 0, false, 0);
				BoomboxPlugin.Log("Playing audio!");
			}
		}

		private static GameObject GetOrCreateSpeaker(PlayerControllerB player)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = ((Component)player).gameObject.transform.Find("Speaker");
			GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				BoomboxPlugin.Log("No speaker found, creating a new one...");
				GameObject val2 = new GameObject("Speaker");
				val2.transform.parent = ((Component)player).transform;
				val2.transform.localPosition = Vector3.zero;
				val2.AddComponent<AudioSource>();
				val2.AddComponent<AudioHighPassFilter>();
				val2.AddComponent<AudioLowPassFilter>();
				return val2;
			}
			BoomboxPlugin.Log("Speaker found!");
			return val;
		}

		private static bool VoiceChanged(PlayerControllerB player, string chatMessage)
		{
			if (chatMessage.StartsWith("!voice "))
			{
				string[] array = chatMessage.Split(new char[1] { ' ' });
				if (array[1] == "david" || array[1] == "zira")
				{
					BoomboxPlugin.Log("Switched voice to: " + array[1]);
					UserToVoice.Value[player.playerUsername] = array[1];
					return true;
				}
				BoomboxPlugin.Log("Cleared voice");
				UserToVoice.Value[player.playerUsername] = "none";
				return true;
			}
			return false;
		}

		public static PlayerControllerB[] GetPlayers()
		{
			return HUDManager.Instance.playersManager.allPlayerScripts;
		}
	}
}
namespace BoomboxMod.Voice
{
	public class Message
	{
		public readonly int playerId;

		public readonly string content;

		public Message(int playerId, string content)
		{
			this.playerId = playerId;
			this.content = content;
		}
	}
	public readonly struct MessageData
	{
		public readonly int playerId;

		public readonly float[] buffer;

		public readonly float lengthSeconds;

		public MessageData(int playerId, float[] buffer, float lengthSeconds)
		{
			this.playerId = playerId;
			this.buffer = buffer;
			this.lengthSeconds = lengthSeconds;
		}
	}
}

System.Speech.dll

Decompiled 9 months ago
#define TRACE
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Speech.AudioFormat;
using System.Speech.Internal;
using System.Speech.Internal.GrammarBuilding;
using System.Speech.Internal.ObjectTokens;
using System.Speech.Internal.SapiInterop;
using System.Speech.Internal.SrgsCompiler;
using System.Speech.Internal.SrgsParser;
using System.Speech.Internal.Synthesis;
using System.Speech.Recognition;
using System.Speech.Recognition.SrgsGrammar;
using System.Speech.Synthesis;
using System.Speech.Synthesis.TtsEngine;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.XPath;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using Microsoft.Win32;

[assembly: CompilationRelaxations(8)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
[assembly: AssemblyTitle("System.Speech.dll")]
[assembly: AssemblyDescription("System.Speech.dll")]
[assembly: AssemblyDefaultAlias("System.Speech.dll")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft® .NET Framework")]
[assembly: AssemblyCopyright("© Microsoft Corporation.  All rights reserved.")]
[assembly: AssemblyFileVersion("4.8.9037.0")]
[assembly: AssemblyInformationalVersion("4.8.9037.0")]
[assembly: SatelliteContractVersion("4.0.0.0")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyDelaySign(true)]
[assembly: AssemblyKeyFile("f:\\dd\\wpf\\src\\windows.snk")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)]
[assembly: FileIOPermission(SecurityAction.RequestOptional, Unrestricted = true)]
[assembly: EnvironmentPermission(SecurityAction.RequestOptional, Unrestricted = true)]
[assembly: RegistryPermission(SecurityAction.RequestOptional, Unrestricted = true)]
[assembly: SecurityPermission(SecurityAction.RequestOptional, Unrestricted = true)]
[assembly: PermissionSet(SecurityAction.RequestOptional, Unrestricted = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("4.0.0.0")]
[module: UnverifiableCode]
namespace System.IO
{
	internal static class FileHelper
	{
		[SecurityCritical]
		internal static FileStream CreateAndOpenTemporaryFile(out string filePath, FileAccess fileAccess = FileAccess.Write, FileOptions fileOptions = FileOptions.None, string extension = null, string subFolder = "WPF")
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			int num = 5;
			filePath = null;
			bool flag = SecurityManager.CurrentThreadRequiresSecurityContextCapture();
			string text = Path.GetTempPath();
			if (!string.IsNullOrEmpty(subFolder))
			{
				string text2 = Path.Combine(text, subFolder);
				if (!Directory.Exists(text2))
				{
					if (!flag)
					{
						Directory.CreateDirectory(text2);
					}
					else
					{
						((CodeAccessPermission)new FileIOPermission((FileIOPermissionAccess)3, text)).Assert();
						Directory.CreateDirectory(text2);
						CodeAccessPermission.RevertAssert();
					}
				}
				text = text2;
			}
			if (flag)
			{
				((CodeAccessPermission)new FileIOPermission((FileIOPermissionAccess)3, text)).Assert();
			}
			FileStream fileStream = null;
			while (fileStream == null)
			{
				string text3 = Path.Combine(text, Path.GetRandomFileName());
				if (!string.IsNullOrEmpty(extension))
				{
					text3 = Path.ChangeExtension(text3, extension);
				}
				num--;
				try
				{
					fileStream = new FileStream(text3, FileMode.CreateNew, fileAccess, FileShare.None, 4096, fileOptions);
					filePath = text3;
				}
				catch (Exception ex) when (num > 0 && (ex is IOException || ex is UnauthorizedAccessException))
				{
				}
			}
			return fileStream;
		}

		[SecurityCritical]
		internal static void DeleteTemporaryFile(string filePath)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(filePath))
			{
				if (SecurityManager.CurrentThreadRequiresSecurityContextCapture())
				{
					((CodeAccessPermission)new FileIOPermission((FileIOPermissionAccess)2, filePath)).Assert();
				}
				try
				{
					File.Delete(filePath);
				}
				catch (IOException)
				{
				}
			}
		}
	}
}
namespace System.Speech
{
	internal enum SRID
	{
		NullParamIllegal,
		ArrayOfNullIllegal,
		ParamsEntryNullIllegal,
		Unavailable,
		UnexpectedError,
		CollectionReadOnly,
		StringCanNotBeEmpty,
		EnumInvalid,
		NotSupportedWithThisVersionOfSAPI,
		NotSupportedWithThisVersionOfSAPI2,
		NotSupportedWithThisVersionOfSAPIBaseUri,
		NotSupportedWithThisVersionOfSAPITagFormat,
		NotSupportedWithThisVersionOfSAPICompareOption,
		MustBeGreaterThanZero,
		InvalidXml,
		OperationAborted,
		InvariantCultureInfo,
		DuplicatedEntry,
		StreamMustBeReadable,
		StreamMustBeWriteable,
		StreamMustBeSeekable,
		StreamEndedUnexpectedly,
		CannotReadFromDirectory,
		UnknownMimeFormat,
		CannotLoadResourceFromManifest,
		TokenInUse,
		TokenDeleted,
		TokenUninitialized,
		InvalidTokenId,
		NotFound,
		NoBackSlash,
		InvalidRegistryEntry,
		TokenCannotCreateInstance,
		InvalidXmlFormat,
		IncorrectAttributeValue,
		MissingRequiredAttribute,
		InvalidRuleRefSelf,
		InvalidDynamicExport,
		InvalidToken,
		MetaNameHTTPEquiv,
		EmptyRule,
		InvalidTokenString,
		InvalidQuotedString,
		ExportDynamicRule,
		EmptyDisplayString,
		EmptyPronunciationString,
		InvalidPhoneme,
		MuliplePronunciationString,
		MultipleDisplayString,
		RuleRedefinition,
		EmptyOneOf,
		InvalidGrammarOrdering,
		MinMaxOutOfRange,
		InvalidExampleOrdering,
		GrammarDefTwice,
		UnsupportedFormat,
		InvalidImport,
		DuplicatedRuleName,
		RootRuleAlreadyDefined,
		RuleNameIdConflict,
		RuleNotDynamic,
		StateWithNoArcs,
		NoTerminatingRulePath,
		RuleRefNoUri,
		UnavailableProperty,
		MinGreaterThanMax,
		ReqConfidenceNotSupported,
		SapiPropertiesAndSemantics,
		InvalidAttributeDefinedTwice,
		GrammarCompilerError,
		RuleScriptNotFound,
		DynamicRuleNotFound,
		RuleScriptInvalidParameters,
		RuleScriptInvalidReturnType,
		NoClassname,
		EmbeddedClassLibraryFailed,
		CannotFindClass,
		StrongTypedGrammarNotAGrammar,
		NoScriptsForRules,
		ClassNotPublic,
		MethodNotPublic,
		IncompatibleLanguageProperties,
		IncompatibleNamespaceProperties,
		IncompatibleDebugProperties,
		CannotLoadDotNetSemanticCode,
		InvalidSemanticProcessingType,
		InvalidScriptDefinition,
		InvalidMethodName,
		ConstructorNotAllowed,
		OverloadNotAllowed,
		OnInitOnPublicRule,
		ArgumentMismatch,
		CantGetPropertyFromSerializedInfo,
		CantFindAConstructor,
		TooManyArcs,
		TooManyRulesWithSemanticsGlobals,
		MaxTransitionsCount,
		UnknownElement,
		CircularRuleRef,
		InvalidFlagsSet,
		RuleDefinedMultipleTimes,
		RuleDefinedMultipleTimes2,
		RuleNotDefined,
		RootNotDefined,
		InvalidLanguage,
		InvalidRuleId,
		InvalidRepeatProbability,
		InvalidConfidence,
		InvalidMinRepeat,
		InvalidMaxRepeat,
		InvalidWeight,
		InvalidName,
		InvalidValueType,
		TagFormatNotSet,
		NoName,
		NoName1,
		InvalidSpecialRuleRef,
		InvalidRuleRef,
		InvalidNotEmptyElement,
		InvalidEmptyElement,
		InvalidEmptyRule,
		UndefRuleRef,
		UnsupportedLanguage,
		UnsupportedPhoneticAlphabet,
		UnsupportedLexicon,
		InvalidScriptAttribute,
		NoLanguageSet,
		MethodAttributeDefinedMultipeTimes,
		RuleAttributeDefinedMultipeTimes,
		InvalidAssemblyReferenceAttribute,
		InvalidImportNamespaceAttribute,
		NoUriForSpecialRuleRef,
		NoAliasForSpecialRuleRef,
		NoSmlData,
		InvalidNameValueProperty,
		InvalidTagInAnEmptyItem,
		InvalidSrgs,
		InvalidSrgsNamespace,
		Line,
		Position,
		InvalidVersion,
		InvalidTagFormat,
		MissingTagFormat,
		InvalidGrammarMode,
		InvalidGrammarAttribute,
		InvalidRuleAttribute,
		InvalidRulerefAttribute,
		InvalidOneOfAttribute,
		InvalidItemAttribute,
		InvalidTokenAttribute,
		InvalidItemRepeatAttribute,
		InvalidReqConfAttribute,
		InvalidTagAttribute,
		InvalidLexiconAttribute,
		InvalidMetaAttribute,
		InvalidItemAttribute2,
		InvalidElement,
		InvalidRuleScope,
		InvalidDynamicSetting,
		InvalidSubsetAttribute,
		InvalidVoiceElementInPromptOutput,
		NoRuleId,
		PromptBuilderInvalideState,
		PromptBuilderStateEnded,
		PromptBuilderStateSentence,
		PromptBuilderStateParagraph,
		PromptBuilderStateVoice,
		PromptBuilderStateStyle,
		PromptBuilderAgeOutOfRange,
		PromptBuilderMismatchStyle,
		PromptBuilderMismatchVoice,
		PromptBuilderMismatchParagraph,
		PromptBuilderMismatchSentence,
		PromptBuilderNestedParagraph,
		PromptBuilderNestedSentence,
		PromptBuilderInvalidAttribute,
		PromptBuilderInvalidElement,
		PromptBuilderInvalidVariant,
		PromptBuilderDatabaseName,
		PromptAsyncOperationCancelled,
		SynthesizerPauseResumeMismatched,
		SynthesizerInvalidMediaType,
		SynthesizerUnknownMediaType,
		SynthesizerSpeakError,
		SynthesizerInvalidWaveFile,
		SynthesizerPromptInUse,
		SynthesizerUnknownPriority,
		SynthesizerUnknownEvent,
		SynthesizerVoiceFailed,
		SynthesizerSetVoiceNoMatch,
		SynthesizerNoCulture,
		SynthesizerSyncSpeakWhilePaused,
		SynthesizerSyncSetOutputWhilePaused,
		SynthesizerNoCulture2,
		SynthesizerNoSpeak,
		SynthesizerSetOutputSpeaking,
		InvalidSpeakAttribute,
		UnsupportedAlphabet,
		GrammarInvalidWeight,
		GrammarInvalidPriority,
		DictationInvalidTopic,
		DictationTopicNotFound,
		RecognizerGrammarNotFound,
		RecognizerRuleNotFound,
		RecognizerInvalidBinaryGrammar,
		RecognizerRuleNotFoundStream,
		RecognizerNoRootRuleToActivate,
		RecognizerNoRootRuleToActivate1,
		RecognizerRuleActivationFailed,
		RecognizerAlreadyRecognizing,
		RecognizerHasNoGrammar,
		NegativeTimesNotSupported,
		AudioDeviceFormatError,
		AudioDeviceError,
		AudioDeviceInternalError,
		RecognizerNotFound,
		RecognizerNotEnabled,
		RecognitionNotSupported,
		RecognitionNotSupportedOn64bit,
		GrammarAlreadyLoaded,
		RecognizerNoInputSource,
		GrammarNotLoaded,
		GrammarLoadingInProgress,
		GrammarLoadFailed,
		GrammarWrongRecognizer,
		NotSupportedOnDictationGrammars,
		LocalFilesOnly,
		NotValidAudioFile,
		NotValidAudioStream,
		FileNotFound,
		CannotSetPriorityOnDictation,
		RecognizerUpdateTableTooLarge,
		MaxAlternatesInvalid,
		RecognizerSettingGetError,
		RecognizerSettingUpdateError,
		RecognizerSettingNotSupported,
		ResourceUsageOutOfRange,
		RateOutOfRange,
		EndSilenceOutOfRange,
		RejectionThresholdOutOfRange,
		ReferencedGrammarNotFound,
		SapiErrorRuleNotFound2,
		NoAudioAvailable,
		ResultNotGrammarAvailable,
		ResultInvalidFormat,
		UnhandledVariant,
		DupSemanticKey,
		DupSemanticValue,
		CannotUseCustomFormat,
		NoPromptEngine,
		NoPromptEngineInterface,
		SeekNotSupported,
		ExtraDataNotPresent,
		BitsPerSampleInvalid,
		DataBlockSizeInvalid,
		NotWholeNumberBlocks,
		BlockSignatureInvalid,
		NumberOfSamplesInvalid,
		SapiErrorUninitialized,
		SapiErrorAlreadyInitialized,
		SapiErrorNotSupportedFormat,
		SapiErrorInvalidFlags,
		SapiErrorEndOfStream,
		SapiErrorDeviceBusy,
		SapiErrorDeviceNotSupported,
		SapiErrorDeviceNotEnabled,
		SapiErrorNoDriver,
		SapiErrorFileMustBeUnicode,
		InsufficientData,
		SapiErrorInvalidPhraseID,
		SapiErrorBufferTooSmall,
		SapiErrorFormatNotSpecified,
		SapiErrorAudioStopped0,
		AudioPaused,
		SapiErrorRuleNotFound,
		SapiErrorTTSEngineException,
		SapiErrorTTSNLPException,
		SapiErrorEngineBUSY,
		AudioConversionEnabled,
		NoHypothesisAvailable,
		SapiErrorCantCreate,
		AlreadyInLex,
		SapiErrorNotInLex,
		LexNothingToSync,
		SapiErrorLexVeryOutOfSync,
		SapiErrorUndefinedForwardRuleRef,
		SapiErrorEmptyRule,
		SapiErrorGrammarCompilerInternalError,
		SapiErrorRuleNotDynamic,
		SapiErrorDuplicateRuleName,
		SapiErrorDuplicateResourceName,
		SapiErrorTooManyGrammars,
		SapiErrorCircularReference,
		SapiErrorInvalidImport,
		SapiErrorInvalidWAVFile,
		RequestPending,
		SapiErrorAllWordsOptional,
		SapiErrorInstanceChangeInvalid,
		SapiErrorRuleNameIdConflict,
		SapiErrorNoRules,
		SapiErrorCircularRuleRef,
		NoParseFound,
		SapiErrorInvalidHandle,
		SapiErrorRemoteCallTimedout,
		SapiErrorAudioBufferOverflow,
		SapiErrorNoAudioData,
		SapiErrorDeadAlternate,
		SapiErrorHighLowConfidence,
		SapiErrorInvalidFormatString,
		SPNotSupportedOnStreamInput,
		SapiErrorAppLexReadOnly,
		SapiErrorNoTerminatingRulePath,
		WordExistsWithoutPronunciation,
		SapiErrorStreamClosed,
		SapiErrorNoMoreItems,
		SapiErrorNotFound,
		SapiErrorInvalidAudioState,
		SapiErrorGenericMMSYS,
		SapiErrorMarshalerException,
		SapiErrorNotDynamicGrammar,
		SapiErrorAmbiguousProperty,
		SapiErrorInvalidRegistrykey,
		SapiErrorInvalidTokenId,
		SapiErrorXMLBadSyntax,
		SapiErrorXMLResourceNotFound,
		SapiErrorTokenInUse,
		SapiErrorTokenDeleted,
		SapiErrorMultilingualNotSupported,
		SapiErrorExportDynamicRule,
		SapiErrorSTGF,
		SapiErrorWordFormat,
		SapiErrorStreamNotActive,
		SapiErrorEngineResponseInvalid,
		SapiErrorSREngineException,
		SapiErrorStreamPosInvalid,
		SapiErrorRecognizerInactive,
		SapiErrorRemoteCallOnWrongThread,
		SapiErrorRemoteProcessTerminated,
		SapiErrorRemoteProcessAlreadyRunning,
		SapiErrorLangIdMismatch,
		SapiErrorPartialParseFound,
		SapiErrorNotTopLevelRule,
		SapiErrorNoRuleActive,
		SapiErrorLexRequiresCookie,
		SapiErrorStreamUninitialized,
		SapiErrorUnused0,
		SapiErrorNotSupportedLang,
		SapiErrorVoicePaused,
		SapiErrorAudioBufferUnderflow,
		SapiErrorAudioStoppedUnexpectedly,
		SapiErrorNoWordPronunciation,
		SapiErrorAlternatesWouldBeInconsistent,
		SapiErrorNotSupportedForSharedRecognizer,
		SapiErrorTimeOut,
		SapiErrorReenterSynchronize,
		SapiErrorStateWithNoArcs,
		SapiErrorNotActiveSession,
		SapiErrorAlreadyDeleted,
		SapiErrorAudioStopped,
		SapiErrorRecoXMLGenerationFail,
		SapiErrorSMLGenerationFail,
		SapiErrorNotPromptVoice,
		SapiErrorRootRuleAlreadyDefined,
		SapiErrorUnused1,
		SapiErrorUnused2,
		SapiErrorUnused3,
		SapiErrorUnused4,
		SapiErrorUnused5,
		SapiErrorUnused6,
		SapiErrorScriptDisallowed,
		SapiErrorRemoteCallTimedOutStart,
		SapiErrorRemoteCallTimedOutConnect,
		SapiErrorSecMgrChangeNotAllowed,
		SapiErrorCompleteButExtendable,
		SapiErrorFailedToDeleteFile,
		SapiErrorSharedEngineDisabled,
		SapiErrorRecognizerNotFound,
		SapiErrorAudioNotFound,
		SapiErrorNoVowel,
		SapiErrorNotSupportedPhoneme,
		SapiErrorNoRulesToActivate,
		SapiErrorNoWordEntryNotification,
		SapiErrorWordNeedsNormalization,
		SapiErrorCannotNormalize,
		LimitReached,
		NotSupported,
		SapiErrorTopicNotADaptable,
		SapiErrorPhonemeConversion,
		SapiErrorNotSupportedForInprocRecognizer
	}
	internal static class SR
	{
		private static ResourceManager _resourceManager = new ResourceManager("ExceptionStringTable", typeof(SR).Assembly);

		internal static string Get(SRID id, params object[] args)
		{
			string text = _resourceManager.GetString(id.ToString());
			if (string.IsNullOrEmpty(text))
			{
				text = _resourceManager.GetString("Unavailable");
			}
			else if (args != null && args.Length != 0)
			{
				text = string.Format(CultureInfo.InvariantCulture, text, args);
			}
			return text;
		}
	}
}
namespace System.Speech.Synthesis
{
	public class BookmarkReachedEventArgs : PromptEventArgs
	{
		private string _bookmark;

		private TimeSpan _audioPosition;

		public string Bookmark => _bookmark;

		public TimeSpan AudioPosition => _audioPosition;

		internal BookmarkReachedEventArgs(Prompt prompt, string bookmark, TimeSpan audioPosition)
			: base(prompt)
		{
			_bookmark = bookmark;
			_audioPosition = audioPosition;
		}
	}
	[DebuggerDisplay("{_text}")]
	public class FilePrompt : Prompt
	{
		public FilePrompt(string path, SynthesisMediaType media)
			: this(new Uri(path, UriKind.Relative), media)
		{
		}

		public FilePrompt(Uri promptFile, SynthesisMediaType media)
			: base(promptFile, media)
		{
		}
	}
	[DebuggerDisplay("{VoiceInfo.Name} [{Enabled ? \"Enabled\" : \"Disabled\"}]")]
	public class InstalledVoice
	{
		private VoiceInfo _voice;

		private bool _enabled;

		private VoiceSynthesis _voiceSynthesizer;

		public VoiceInfo VoiceInfo => _voice;

		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				SetEnabledFlag(value, switchContext: true);
			}
		}

		internal InstalledVoice(VoiceSynthesis voiceSynthesizer, VoiceInfo voice)
		{
			_voiceSynthesizer = voiceSynthesizer;
			_voice = voice;
			_enabled = true;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is InstalledVoice installedVoice))
			{
				return false;
			}
			if (VoiceInfo.Name == installedVoice.VoiceInfo.Name && VoiceInfo.Age == installedVoice.VoiceInfo.Age && VoiceInfo.Gender == installedVoice.VoiceInfo.Gender)
			{
				return VoiceInfo.Culture.Equals(installedVoice.VoiceInfo.Culture);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return VoiceInfo.Name.GetHashCode();
		}

		internal static InstalledVoice Find(List<InstalledVoice> list, VoiceInfo voiceId)
		{
			foreach (InstalledVoice item in list)
			{
				if (item.Enabled && item.VoiceInfo.Equals(voiceId))
				{
					return item;
				}
			}
			return null;
		}

		internal static InstalledVoice FirstEnabled(List<InstalledVoice> list, CultureInfo culture)
		{
			InstalledVoice installedVoice = null;
			foreach (InstalledVoice item in list)
			{
				if (item.Enabled)
				{
					if (Helpers.CompareInvariantCulture(item.VoiceInfo.Culture, culture))
					{
						return item;
					}
					if (installedVoice == null)
					{
						installedVoice = item;
					}
				}
			}
			return installedVoice;
		}

		internal void SetEnabledFlag(bool value, bool switchContext)
		{
			try
			{
				if (_enabled == value)
				{
					return;
				}
				_enabled = value;
				if (!_enabled)
				{
					if (_voice.Equals(_voiceSynthesizer.CurrentVoice(switchContext).VoiceInfo))
					{
						_voiceSynthesizer.Voice = null;
					}
				}
				else
				{
					_voiceSynthesizer.Voice = null;
				}
			}
			catch (InvalidOperationException)
			{
				_voiceSynthesizer.Voice = null;
			}
		}
	}
	[DebuggerDisplay("{_text}")]
	public class Prompt
	{
		internal string _text;

		internal Uri _audio;

		internal SynthesisMediaType _media;

		internal bool _syncSpeak;

		internal Exception _exception;

		private bool _completed;

		private object _synthesizer;

		private static ResourceLoader _resourceLoader = new ResourceLoader();

		public bool IsCompleted
		{
			get
			{
				return _completed;
			}
			internal set
			{
				_completed = value;
			}
		}

		internal object Synthesizer
		{
			set
			{
				if (value != null && (_synthesizer != null || _completed))
				{
					throw new ArgumentException(SR.Get(SRID.SynthesizerPromptInUse), "value");
				}
				_synthesizer = value;
			}
		}

		public Prompt(string textToSpeak)
			: this(textToSpeak, SynthesisTextFormat.Text)
		{
		}

		public Prompt(PromptBuilder promptBuilder)
		{
			Helpers.ThrowIfNull(promptBuilder, "promptBuilder");
			_text = promptBuilder.ToXml();
			_media = SynthesisMediaType.Ssml;
		}

		public Prompt(string textToSpeak, SynthesisTextFormat media)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			if ((uint)(_media = (SynthesisMediaType)media) <= 1u)
			{
				_text = textToSpeak;
				return;
			}
			throw new ArgumentException(SR.Get(SRID.SynthesizerUnknownMediaType), "media");
		}

		internal Prompt(Uri promptFile, SynthesisMediaType media)
		{
			Helpers.ThrowIfNull(promptFile, "promptFile");
			switch (_media = media)
			{
			case SynthesisMediaType.Text:
			case SynthesisMediaType.Ssml:
			{
				string mimeType;
				Uri baseUri;
				string localPath;
				using Stream stream = _resourceLoader.LoadFile(promptFile, out mimeType, out baseUri, out localPath);
				try
				{
					using TextReader textReader = new StreamReader(stream);
					_text = textReader.ReadToEnd();
					break;
				}
				finally
				{
					_resourceLoader.UnloadFile(localPath);
				}
			}
			case SynthesisMediaType.WaveAudio:
				_text = promptFile.ToString();
				_audio = promptFile;
				break;
			default:
				throw new ArgumentException(SR.Get(SRID.SynthesizerUnknownMediaType), "media");
			}
		}
	}
	public enum SynthesisMediaType
	{
		Text,
		Ssml,
		WaveAudio
	}
	public enum SynthesisTextFormat
	{
		Text,
		Ssml
	}
	internal enum PromptPriority
	{
		Normal,
		High
	}
	[Serializable]
	public class PromptBuilder
	{
		internal enum SsmlState
		{
			Header = 1,
			Paragraph = 2,
			Sentence = 4,
			StyleEmphasis = 8,
			StyleProsody = 0x10,
			Voice = 0x20,
			Ended = 0x40
		}

		[Serializable]
		private struct StackElement
		{
			internal SsmlElement _possibleChildren;

			internal SsmlState _state;

			internal CultureInfo _culture;

			internal StackElement(SsmlElement possibleChildren, SsmlState state, CultureInfo culture)
			{
				_possibleChildren = possibleChildren;
				_state = state;
				_culture = culture;
			}
		}

		private enum ElementType
		{
			Prosody,
			Emphasis,
			SayAs,
			Phoneme,
			Sub,
			Break,
			Audio,
			Bookmark,
			StartVoice,
			StartParagraph,
			StartSentence,
			EndSentence,
			EndParagraph,
			StartStyle,
			EndStyle,
			EndVoice,
			Text,
			SsmlMarkup
		}

		[Serializable]
		private struct AttributeItem
		{
			internal string _key;

			internal string _value;

			internal string _namespace;

			internal AttributeItem(string key, string value)
			{
				_key = key;
				_value = value;
				_namespace = null;
			}

			internal AttributeItem(string ns, string key, string value)
				: this(key, value)
			{
				_namespace = ns;
			}
		}

		[Serializable]
		private class Element
		{
			internal ElementType _type;

			internal string _text;

			internal Collection<AttributeItem> _attributes;

			internal Element(ElementType type)
			{
				_type = type;
			}

			internal Element(ElementType type, string text)
				: this(type)
			{
				_text = text;
			}
		}

		private Stack<StackElement> _elementStack = new Stack<StackElement>();

		private CultureInfo _culture;

		private List<Element> _elements = new List<Element>();

		private static ResourceLoader _resourceLoader = new ResourceLoader();

		private const string _xmlnsDefault = "http://www.w3.org/2001/10/synthesis";

		private static readonly string[] _promptBuilderElementName = new string[11]
		{
			"prosody", "emphasis", "say-as", "phoneme", "sub", "break", "audio", "mark", "voice", "p",
			"s"
		};

		public bool IsEmpty => _elements.Count == 0;

		public CultureInfo Culture
		{
			get
			{
				return _culture;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				_culture = value;
			}
		}

		public PromptBuilder()
			: this(CultureInfo.CurrentUICulture)
		{
		}

		public PromptBuilder(CultureInfo culture)
		{
			Helpers.ThrowIfNull(culture, "culture");
			if (culture.Equals(CultureInfo.InvariantCulture))
			{
				throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture");
			}
			_culture = culture;
			ClearContent();
		}

		public void ClearContent()
		{
			_elements.Clear();
			_elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.ParagraphOrSentence | SsmlElement.Lexicon | SsmlElement.Meta | SsmlElement.MetaData, SsmlState.Header, _culture));
		}

		public void AppendText(string textToSpeak)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			_elements.Add(new Element(ElementType.Text, textToSpeak));
		}

		public void AppendText(string textToSpeak, PromptRate rate)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			if (rate < PromptRate.NotSet || rate > PromptRate.ExtraSlow)
			{
				throw new ArgumentOutOfRangeException("rate");
			}
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			Element element = new Element(ElementType.Prosody, textToSpeak);
			_elements.Add(element);
			string value = null;
			switch (rate)
			{
			case PromptRate.ExtraFast:
				value = "x-fast";
				break;
			case PromptRate.ExtraSlow:
				value = "x-slow";
				break;
			default:
				value = rate.ToString().ToLowerInvariant();
				break;
			case PromptRate.NotSet:
				break;
			}
			if (!string.IsNullOrEmpty(value))
			{
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("rate", value));
			}
		}

		public void AppendText(string textToSpeak, PromptVolume volume)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			if (volume < PromptVolume.NotSet || volume > PromptVolume.Default)
			{
				throw new ArgumentOutOfRangeException("volume");
			}
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			Element element = new Element(ElementType.Prosody, textToSpeak);
			_elements.Add(element);
			string value = null;
			switch (volume)
			{
			case PromptVolume.ExtraSoft:
				value = "x-soft";
				break;
			case PromptVolume.ExtraLoud:
				value = "x-loud";
				break;
			default:
				value = volume.ToString().ToLowerInvariant();
				break;
			case PromptVolume.NotSet:
				break;
			}
			if (!string.IsNullOrEmpty(value))
			{
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("volume", value));
			}
		}

		public void AppendText(string textToSpeak, PromptEmphasis emphasis)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			if (emphasis < PromptEmphasis.NotSet || emphasis > PromptEmphasis.Reduced)
			{
				throw new ArgumentOutOfRangeException("emphasis");
			}
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			Element element = new Element(ElementType.Emphasis, textToSpeak);
			_elements.Add(element);
			if (emphasis != 0)
			{
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("level", emphasis.ToString().ToLowerInvariant()));
			}
		}

		public void StartStyle(PromptStyle style)
		{
			Helpers.ThrowIfNull(style, "style");
			StackElement stackElement = _elementStack.Peek();
			ValidateElement(stackElement, SsmlElement.Prosody);
			SsmlState ssmlState = (SsmlState)0;
			SsmlElement possibleChildren = stackElement._possibleChildren;
			_elements.Add(new Element(ElementType.StartStyle));
			if (style.Emphasis != 0)
			{
				Element element = new Element(ElementType.Emphasis);
				_elements.Add(element);
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("level", style.Emphasis.ToString().ToLowerInvariant()));
				possibleChildren = SsmlElement.AudioMarkTextWithStyle;
				ssmlState = SsmlState.StyleEmphasis;
			}
			if (style.Rate != 0 || style.Volume != 0)
			{
				if (ssmlState != 0)
				{
					_elements.Add(new Element(ElementType.StartStyle));
				}
				Element element2 = new Element(ElementType.Prosody);
				_elements.Add(element2);
				if (style.Rate != 0)
				{
					string value = style.Rate switch
					{
						PromptRate.ExtraFast => "x-fast", 
						PromptRate.ExtraSlow => "x-slow", 
						_ => style.Rate.ToString().ToLowerInvariant(), 
					};
					element2._attributes = new Collection<AttributeItem>();
					element2._attributes.Add(new AttributeItem("rate", value));
				}
				if (style.Volume != 0)
				{
					string value2 = style.Volume switch
					{
						PromptVolume.ExtraSoft => "x-soft", 
						PromptVolume.ExtraLoud => "x-loud", 
						_ => style.Volume.ToString().ToLowerInvariant(), 
					};
					if (element2._attributes == null)
					{
						element2._attributes = new Collection<AttributeItem>();
					}
					element2._attributes.Add(new AttributeItem("volume", value2));
				}
				possibleChildren = SsmlElement.AudioMarkTextWithStyle | SsmlElement.ParagraphOrSentence;
				ssmlState |= SsmlState.StyleProsody;
			}
			_elementStack.Push(new StackElement(possibleChildren, ssmlState, stackElement._culture));
		}

		public void EndStyle()
		{
			StackElement stackElement = _elementStack.Pop();
			if (stackElement._state != 0)
			{
				if ((stackElement._state & (SsmlState)24) == 0)
				{
					throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchStyle));
				}
				_elements.Add(new Element(ElementType.EndStyle));
				if (stackElement._state == (SsmlState)24)
				{
					_elements.Add(new Element(ElementType.EndStyle));
				}
			}
		}

		public void StartVoice(VoiceInfo voice)
		{
			Helpers.ThrowIfNull(voice, "voice");
			if (!VoiceInfo.ValidateGender(voice.Gender))
			{
				throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceGender"), "voice");
			}
			if (!VoiceInfo.ValidateAge(voice.Age))
			{
				throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceAge"), "voice");
			}
			StackElement stackElement = _elementStack.Peek();
			ValidateElement(stackElement, SsmlElement.Voice);
			CultureInfo culture = ((voice.Culture == null) ? stackElement._culture : voice.Culture);
			Element element = new Element(ElementType.StartVoice);
			element._attributes = new Collection<AttributeItem>();
			_elements.Add(element);
			if (!string.IsNullOrEmpty(voice.Name))
			{
				element._attributes.Add(new AttributeItem("name", voice.Name));
			}
			if (voice.Culture != null)
			{
				element._attributes.Add(new AttributeItem("xml", "lang", voice.Culture.Name));
			}
			if (voice.Gender != 0)
			{
				element._attributes.Add(new AttributeItem("gender", voice.Gender.ToString().ToLowerInvariant()));
			}
			if (voice.Age != 0)
			{
				element._attributes.Add(new AttributeItem("age", ((int)voice.Age).ToString(CultureInfo.InvariantCulture)));
			}
			if (voice.Variant >= 0)
			{
				element._attributes.Add(new AttributeItem("variant", voice.Variant.ToString(CultureInfo.InvariantCulture)));
			}
			_elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.Sentence, SsmlState.Voice, culture));
		}

		public void StartVoice(string name)
		{
			Helpers.ThrowIfEmptyOrNull(name, "name");
			StartVoice(new VoiceInfo(name));
		}

		public void StartVoice(VoiceGender gender)
		{
			StartVoice(new VoiceInfo(gender));
		}

		public void StartVoice(VoiceGender gender, VoiceAge age)
		{
			StartVoice(new VoiceInfo(gender, age));
		}

		public void StartVoice(VoiceGender gender, VoiceAge age, int voiceAlternate)
		{
			StartVoice(new VoiceInfo(gender, age, voiceAlternate));
		}

		public void StartVoice(CultureInfo culture)
		{
			StartVoice(new VoiceInfo(culture));
		}

		public void EndVoice()
		{
			if (_elementStack.Pop()._state != SsmlState.Voice)
			{
				throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchVoice));
			}
			_elements.Add(new Element(ElementType.EndVoice));
		}

		public void StartParagraph()
		{
			StartParagraph(null);
		}

		public void StartParagraph(CultureInfo culture)
		{
			StackElement stackElement = _elementStack.Peek();
			ValidateElement(stackElement, SsmlElement.Paragraph);
			Element element = new Element(ElementType.StartParagraph);
			_elements.Add(element);
			if (culture != null)
			{
				if (culture.Equals(CultureInfo.InvariantCulture))
				{
					throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture");
				}
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("xml", "lang", culture.Name));
			}
			else
			{
				culture = stackElement._culture;
			}
			_elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle | SsmlElement.Sentence, SsmlState.Paragraph, culture));
		}

		public void EndParagraph()
		{
			if (_elementStack.Pop()._state != SsmlState.Paragraph)
			{
				throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchParagraph));
			}
			_elements.Add(new Element(ElementType.EndParagraph));
		}

		public void StartSentence()
		{
			StartSentence(null);
		}

		public void StartSentence(CultureInfo culture)
		{
			StackElement stackElement = _elementStack.Peek();
			ValidateElement(stackElement, SsmlElement.Sentence);
			Element element = new Element(ElementType.StartSentence);
			_elements.Add(element);
			if (culture != null)
			{
				if (culture.Equals(CultureInfo.InvariantCulture))
				{
					throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture");
				}
				element._attributes = new Collection<AttributeItem>();
				element._attributes.Add(new AttributeItem("xml", "lang", culture.Name));
			}
			else
			{
				culture = stackElement._culture;
			}
			_elementStack.Push(new StackElement(SsmlElement.AudioMarkTextWithStyle, SsmlState.Sentence, culture));
		}

		public void EndSentence()
		{
			if (_elementStack.Pop()._state != SsmlState.Sentence)
			{
				throw new InvalidOperationException(SR.Get(SRID.PromptBuilderMismatchSentence));
			}
			_elements.Add(new Element(ElementType.EndSentence));
		}

		public void AppendTextWithHint(string textToSpeak, SayAs sayAs)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			if (sayAs < SayAs.SpellOut || sayAs > SayAs.Text)
			{
				throw new ArgumentOutOfRangeException("sayAs");
			}
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			if (sayAs != SayAs.Text)
			{
				Element element = new Element(ElementType.SayAs, textToSpeak);
				_elements.Add(element);
				element._attributes = new Collection<AttributeItem>();
				string value = null;
				string value2 = null;
				switch (sayAs)
				{
				case SayAs.SpellOut:
					value = "characters";
					break;
				case SayAs.NumberOrdinal:
					value = "ordinal";
					break;
				case SayAs.NumberCardinal:
					value = "cardinal";
					break;
				case SayAs.Date:
					value = "date";
					break;
				case SayAs.DayMonthYear:
					value = "date";
					value2 = "dmy";
					break;
				case SayAs.MonthDayYear:
					value = "date";
					value2 = "mdy";
					break;
				case SayAs.YearMonthDay:
					value = "date";
					value2 = "ymd";
					break;
				case SayAs.YearMonth:
					value = "date";
					value2 = "ym";
					break;
				case SayAs.MonthYear:
					value = "date";
					value2 = "my";
					break;
				case SayAs.MonthDay:
					value = "date";
					value2 = "md";
					break;
				case SayAs.DayMonth:
					value = "date";
					value2 = "dm";
					break;
				case SayAs.Year:
					value = "date";
					value2 = "y";
					break;
				case SayAs.Month:
					value = "date";
					value2 = "m";
					break;
				case SayAs.Day:
					value = "date";
					value2 = "d";
					break;
				case SayAs.Time:
					value = "time";
					break;
				case SayAs.Time24:
					value = "time";
					value2 = "hms24";
					break;
				case SayAs.Time12:
					value = "time";
					value2 = "hms12";
					break;
				case SayAs.Telephone:
					value = "telephone";
					break;
				}
				element._attributes.Add(new AttributeItem("interpret-as", value));
				if (!string.IsNullOrEmpty(value2))
				{
					element._attributes.Add(new AttributeItem("format", value2));
				}
			}
			else
			{
				AppendText(textToSpeak);
			}
		}

		public void AppendTextWithHint(string textToSpeak, string sayAs)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			Helpers.ThrowIfEmptyOrNull(sayAs, "sayAs");
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			Element element = new Element(ElementType.SayAs, textToSpeak);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("interpret-as", sayAs));
		}

		public void AppendTextWithPronunciation(string textToSpeak, string pronunciation)
		{
			Helpers.ThrowIfEmptyOrNull(textToSpeak, "textToSpeak");
			Helpers.ThrowIfEmptyOrNull(pronunciation, "pronunciation");
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			PhonemeConverter.ValidateUpsIds(pronunciation);
			Element element = new Element(ElementType.Phoneme, textToSpeak);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("ph", pronunciation));
		}

		public void AppendTextWithAlias(string textToSpeak, string substitute)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			Helpers.ThrowIfNull(substitute, "substitute");
			ValidateElement(_elementStack.Peek(), SsmlElement.Text);
			Element element = new Element(ElementType.Sub, textToSpeak);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("alias", substitute));
		}

		public void AppendBreak()
		{
			ValidateElement(_elementStack.Peek(), SsmlElement.Break);
			_elements.Add(new Element(ElementType.Break));
		}

		public void AppendBreak(PromptBreak strength)
		{
			ValidateElement(_elementStack.Peek(), SsmlElement.Break);
			Element element = new Element(ElementType.Break);
			_elements.Add(element);
			string text = null;
			text = strength switch
			{
				PromptBreak.None => "none", 
				PromptBreak.ExtraSmall => "x-weak", 
				PromptBreak.Small => "weak", 
				PromptBreak.Medium => "medium", 
				PromptBreak.Large => "strong", 
				PromptBreak.ExtraLarge => "x-strong", 
				_ => throw new ArgumentNullException("strength"), 
			};
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("strength", text));
		}

		public void AppendBreak(TimeSpan duration)
		{
			ValidateElement(_elementStack.Peek(), SsmlElement.Break);
			if (duration.Ticks < 0)
			{
				throw new ArgumentOutOfRangeException("duration");
			}
			Element element = new Element(ElementType.Break);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("time", duration.TotalMilliseconds + "ms"));
		}

		public void AppendAudio(string path)
		{
			Helpers.ThrowIfEmptyOrNull(path, "path");
			Uri audioFile;
			try
			{
				audioFile = new Uri(path, UriKind.RelativeOrAbsolute);
			}
			catch (UriFormatException ex)
			{
				throw new ArgumentException(ex.Message, path, ex);
			}
			ValidateElement(_elementStack.Peek(), SsmlElement.Audio);
			AppendAudio(audioFile);
		}

		public void AppendAudio(Uri audioFile)
		{
			Helpers.ThrowIfNull(audioFile, "audioFile");
			ValidateElement(_elementStack.Peek(), SsmlElement.Audio);
			Element element = new Element(ElementType.Audio);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("src", audioFile.ToString()));
		}

		public void AppendAudio(Uri audioFile, string alternateText)
		{
			Helpers.ThrowIfNull(audioFile, "audioFile");
			Helpers.ThrowIfNull(alternateText, "alternateText");
			ValidateElement(_elementStack.Peek(), SsmlElement.Audio);
			Element element = new Element(ElementType.Audio, alternateText);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("src", audioFile.ToString()));
		}

		public void AppendBookmark(string bookmarkName)
		{
			Helpers.ThrowIfEmptyOrNull(bookmarkName, "bookmarkName");
			ValidateElement(_elementStack.Peek(), SsmlElement.Mark);
			Element element = new Element(ElementType.Bookmark);
			_elements.Add(element);
			element._attributes = new Collection<AttributeItem>();
			element._attributes.Add(new AttributeItem("name", bookmarkName));
		}

		public void AppendPromptBuilder(PromptBuilder promptBuilder)
		{
			Helpers.ThrowIfNull(promptBuilder, "promptBuilder");
			StringReader stringReader = new StringReader(promptBuilder.ToXml());
			XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
			AppendSsml(xmlTextReader);
			xmlTextReader.Close();
			stringReader.Close();
		}

		public void AppendSsml(string path)
		{
			Helpers.ThrowIfEmptyOrNull(path, "path");
			AppendSsml(new Uri(path, UriKind.Relative));
		}

		public void AppendSsml(Uri ssmlFile)
		{
			Helpers.ThrowIfNull(ssmlFile, "ssmlFile");
			string localPath;
			Uri redirectedUri;
			using Stream input = _resourceLoader.LoadFile(ssmlFile, out localPath, out redirectedUri);
			try
			{
				AppendSsml(new XmlTextReader(input));
			}
			finally
			{
				_resourceLoader.UnloadFile(localPath);
			}
		}

		public void AppendSsml(XmlReader ssmlFile)
		{
			Helpers.ThrowIfNull(ssmlFile, "ssmlFile");
			AppendSsmlInternal(ssmlFile);
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public void AppendSsmlMarkup(string ssmlMarkup)
		{
			Helpers.ThrowIfEmptyOrNull(ssmlMarkup, "ssmlMarkup");
			_elements.Add(new Element(ElementType.SsmlMarkup, ssmlMarkup));
		}

		public string ToXml()
		{
			using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			using XmlTextWriter writer = new XmlTextWriter(stringWriter);
			WriteXml(writer);
			SsmlState state = _elementStack.Peek()._state;
			if (state != SsmlState.Header)
			{
				string text = SR.Get(SRID.PromptBuilderInvalideState);
				switch (state)
				{
				case SsmlState.Ended:
					text += SR.Get(SRID.PromptBuilderStateEnded);
					break;
				case SsmlState.Sentence:
					text += SR.Get(SRID.PromptBuilderStateSentence);
					break;
				case SsmlState.Paragraph:
					text += SR.Get(SRID.PromptBuilderStateParagraph);
					break;
				case SsmlState.StyleEmphasis:
				case SsmlState.StyleProsody:
				case (SsmlState)24:
					text += SR.Get(SRID.PromptBuilderStateStyle);
					break;
				case SsmlState.Voice:
					text += SR.Get(SRID.PromptBuilderStateVoice);
					break;
				default:
					throw new NotSupportedException();
				}
				throw new InvalidOperationException(text);
			}
			return stringWriter.ToString();
		}

		private void WriteXml(XmlTextWriter writer)
		{
			writer.WriteStartElement("speak");
			writer.WriteAttributeString("version", "1.0");
			writer.WriteAttributeString("xmlns", "http://www.w3.org/2001/10/synthesis");
			writer.WriteAttributeString("xml", "lang", null, _culture.Name);
			bool flag = false;
			foreach (Element element in _elements)
			{
				flag = flag || element._type == ElementType.StartSentence || element._type == ElementType.StartParagraph || element._type == ElementType.StartStyle || element._type == ElementType.StartVoice;
				switch (element._type)
				{
				case ElementType.Text:
					writer.WriteString(element._text);
					break;
				case ElementType.SsmlMarkup:
					writer.WriteRaw(element._text);
					break;
				case ElementType.Prosody:
				case ElementType.Emphasis:
				case ElementType.SayAs:
				case ElementType.Phoneme:
				case ElementType.Sub:
				case ElementType.Break:
				case ElementType.Audio:
				case ElementType.Bookmark:
				case ElementType.StartVoice:
				case ElementType.StartParagraph:
				case ElementType.StartSentence:
					writer.WriteStartElement(_promptBuilderElementName[(int)element._type]);
					if (element._attributes != null)
					{
						foreach (AttributeItem attribute in element._attributes)
						{
							if (attribute._namespace == null)
							{
								writer.WriteAttributeString(attribute._key, attribute._value);
							}
							else
							{
								writer.WriteAttributeString(attribute._namespace, attribute._key, null, attribute._value);
							}
						}
					}
					if (element._text != null)
					{
						writer.WriteString(element._text);
					}
					if (!flag)
					{
						writer.WriteEndElement();
					}
					flag = false;
					break;
				case ElementType.EndSentence:
				case ElementType.EndParagraph:
				case ElementType.EndStyle:
				case ElementType.EndVoice:
					writer.WriteEndElement();
					break;
				default:
					throw new NotSupportedException();
				case ElementType.StartStyle:
					break;
				}
			}
			writer.WriteEndElement();
		}

		private static void ValidateElement(StackElement stackElement, SsmlElement currentElement)
		{
			if ((stackElement._possibleChildren & currentElement) == 0)
			{
				throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, SR.Get(SRID.PromptBuilderInvalidElement), new object[2]
				{
					currentElement.ToString(),
					stackElement._state.ToString()
				}));
			}
		}

		private void AppendSsmlInternal(XmlReader ssmlFile)
		{
			StackElement stackElement = _elementStack.Peek();
			ValidateElement(_elementStack.Peek(), SsmlElement.Voice);
			using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			using (XmlTextWriter writer = new XmlTextWriter(stringWriter))
			{
				TextWriterEngine engine = new TextWriterEngine(writer, stackElement._culture);
				SsmlParser.Parse(ssmlFile, engine, null);
			}
			_elements.Add(new Element(ElementType.SsmlMarkup, stringWriter.ToString()));
		}
	}
	public abstract class PromptEventArgs : AsyncCompletedEventArgs
	{
		private Prompt _prompt;

		public Prompt Prompt => _prompt;

		internal PromptEventArgs(Prompt prompt)
			: base(prompt._exception, prompt._exception != null, prompt)
		{
			_prompt = prompt;
		}
	}
	public class SpeakStartedEventArgs : PromptEventArgs
	{
		internal SpeakStartedEventArgs(Prompt prompt)
			: base(prompt)
		{
		}
	}
	[Serializable]
	public class PromptStyle
	{
		private PromptRate _rate;

		private PromptVolume _volume;

		private PromptEmphasis _emphasis;

		public PromptRate Rate
		{
			get
			{
				return _rate;
			}
			set
			{
				_rate = value;
			}
		}

		public PromptVolume Volume
		{
			get
			{
				return _volume;
			}
			set
			{
				_volume = value;
			}
		}

		public PromptEmphasis Emphasis
		{
			get
			{
				return _emphasis;
			}
			set
			{
				_emphasis = value;
			}
		}

		public PromptStyle()
		{
		}

		public PromptStyle(PromptRate rate)
		{
			Rate = rate;
		}

		public PromptStyle(PromptVolume volume)
		{
			Volume = volume;
		}

		public PromptStyle(PromptEmphasis emphasis)
		{
			Emphasis = emphasis;
		}
	}
	public enum SayAs
	{
		SpellOut,
		NumberOrdinal,
		NumberCardinal,
		Date,
		DayMonthYear,
		MonthDayYear,
		YearMonthDay,
		YearMonth,
		MonthYear,
		MonthDay,
		DayMonth,
		Year,
		Month,
		Day,
		Time,
		Time24,
		Time12,
		Telephone,
		Text
	}
	public enum VoiceGender
	{
		NotSet,
		Male,
		Female,
		Neutral
	}
	public enum VoiceAge
	{
		NotSet = 0,
		Child = 10,
		Teen = 15,
		Adult = 30,
		Senior = 65
	}
	public enum PromptRate
	{
		NotSet,
		ExtraFast,
		Fast,
		Medium,
		Slow,
		ExtraSlow
	}
	public enum PromptVolume
	{
		NotSet,
		Silent,
		ExtraSoft,
		Soft,
		Medium,
		Loud,
		ExtraLoud,
		Default
	}
	public enum PromptEmphasis
	{
		NotSet,
		Strong,
		Moderate,
		None,
		Reduced
	}
	public enum PromptBreak
	{
		None,
		ExtraSmall,
		Small,
		Medium,
		Large,
		ExtraLarge
	}
	public sealed class SpeechSynthesizer : IDisposable
	{
		private VoiceSynthesis _voiceSynthesis;

		private bool _isDisposed;

		private bool paused;

		private Stream _outputStream;

		private bool _closeStreamOnExit;

		public SynthesizerState State => VoiceSynthesizer.State;

		public int Rate
		{
			get
			{
				return VoiceSynthesizer.Rate;
			}
			set
			{
				if (value < -10 || value > 10)
				{
					throw new ArgumentOutOfRangeException("value", SR.Get(SRID.RateOutOfRange));
				}
				VoiceSynthesizer.Rate = value;
			}
		}

		public int Volume
		{
			get
			{
				return VoiceSynthesizer.Volume;
			}
			set
			{
				if (value < 0 || value > 100)
				{
					throw new ArgumentOutOfRangeException("value", SR.Get(SRID.ResourceUsageOutOfRange));
				}
				VoiceSynthesizer.Volume = value;
			}
		}

		public VoiceInfo Voice => VoiceSynthesizer.CurrentVoice(switchContext: true).VoiceInfo;

		private VoiceSynthesis VoiceSynthesizer
		{
			get
			{
				if (_voiceSynthesis == null && _isDisposed)
				{
					throw new ObjectDisposedException("SpeechSynthesizer");
				}
				if (_voiceSynthesis == null)
				{
					WeakReference speechSynthesizer = new WeakReference(this);
					_voiceSynthesis = new VoiceSynthesis(speechSynthesizer);
				}
				return _voiceSynthesis;
			}
		}

		public event EventHandler<SpeakStartedEventArgs> SpeakStarted
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._speakStarted = (EventHandler<SpeakStartedEventArgs>)Delegate.Combine(voiceSynthesizer._speakStarted, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._speakStarted = (EventHandler<SpeakStartedEventArgs>)Delegate.Remove(voiceSynthesizer._speakStarted, value);
			}
		}

		public event EventHandler<SpeakCompletedEventArgs> SpeakCompleted
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._speakCompleted = (EventHandler<SpeakCompletedEventArgs>)Delegate.Combine(voiceSynthesizer._speakCompleted, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._speakCompleted = (EventHandler<SpeakCompletedEventArgs>)Delegate.Remove(voiceSynthesizer._speakCompleted, value);
			}
		}

		public event EventHandler<SpeakProgressEventArgs> SpeakProgress
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.AddEvent(TtsEventId.WordBoundary, ref VoiceSynthesizer._speakProgress, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.RemoveEvent(TtsEventId.WordBoundary, ref VoiceSynthesizer._speakProgress, value);
			}
		}

		public event EventHandler<BookmarkReachedEventArgs> BookmarkReached
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.AddEvent(TtsEventId.Bookmark, ref VoiceSynthesizer._bookmarkReached, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.RemoveEvent(TtsEventId.Bookmark, ref VoiceSynthesizer._bookmarkReached, value);
			}
		}

		public event EventHandler<VoiceChangeEventArgs> VoiceChange
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.AddEvent(TtsEventId.VoiceChange, ref VoiceSynthesizer._voiceChange, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.RemoveEvent(TtsEventId.VoiceChange, ref VoiceSynthesizer._voiceChange, value);
			}
		}

		public event EventHandler<PhonemeReachedEventArgs> PhonemeReached
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.AddEvent(TtsEventId.Phoneme, ref VoiceSynthesizer._phonemeReached, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.RemoveEvent(TtsEventId.Phoneme, ref VoiceSynthesizer._phonemeReached, value);
			}
		}

		public event EventHandler<VisemeReachedEventArgs> VisemeReached
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.AddEvent(TtsEventId.Viseme, ref VoiceSynthesizer._visemeReached, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesizer.RemoveEvent(TtsEventId.Viseme, ref VoiceSynthesizer._visemeReached, value);
			}
		}

		public event EventHandler<StateChangedEventArgs> StateChanged
		{
			[MethodImpl(MethodImplOptions.Synchronized)]
			add
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._stateChanged = (EventHandler<StateChangedEventArgs>)Delegate.Combine(voiceSynthesizer._stateChanged, value);
			}
			[MethodImpl(MethodImplOptions.Synchronized)]
			remove
			{
				Helpers.ThrowIfNull(value, "value");
				VoiceSynthesis voiceSynthesizer = VoiceSynthesizer;
				voiceSynthesizer._stateChanged = (EventHandler<StateChangedEventArgs>)Delegate.Remove(voiceSynthesizer._stateChanged, value);
			}
		}

		~SpeechSynthesizer()
		{
			Dispose(disposing: false);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public void SelectVoice(string name)
		{
			Helpers.ThrowIfEmptyOrNull(name, "name");
			TTSVoice engine = VoiceSynthesizer.GetEngine(name, CultureInfo.CurrentUICulture, VoiceGender.NotSet, VoiceAge.NotSet, 1, switchContext: true);
			if (engine == null || name != engine.VoiceInfo.Name)
			{
				throw new ArgumentException(SR.Get(SRID.SynthesizerSetVoiceNoMatch));
			}
			VoiceSynthesizer.Voice = engine;
		}

		public void SelectVoiceByHints(VoiceGender gender)
		{
			SelectVoiceByHints(gender, VoiceAge.NotSet, 1, CultureInfo.CurrentUICulture);
		}

		public void SelectVoiceByHints(VoiceGender gender, VoiceAge age)
		{
			SelectVoiceByHints(gender, age, 1, CultureInfo.CurrentUICulture);
		}

		public void SelectVoiceByHints(VoiceGender gender, VoiceAge age, int voiceAlternate)
		{
			SelectVoiceByHints(gender, age, voiceAlternate, CultureInfo.CurrentUICulture);
		}

		public void SelectVoiceByHints(VoiceGender gender, VoiceAge age, int voiceAlternate, CultureInfo culture)
		{
			Helpers.ThrowIfNull(culture, "culture");
			if (voiceAlternate < 0)
			{
				throw new ArgumentOutOfRangeException("voiceAlternate", SR.Get(SRID.PromptBuilderInvalidVariant));
			}
			if (!VoiceInfo.ValidateGender(gender))
			{
				throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceGender"), "gender");
			}
			if (!VoiceInfo.ValidateAge(age))
			{
				throw new ArgumentException(SR.Get(SRID.EnumInvalid, "VoiceAge"), "age");
			}
			TTSVoice engine = VoiceSynthesizer.GetEngine(null, culture, gender, age, voiceAlternate, switchContext: true);
			if (engine == null)
			{
				throw new InvalidOperationException(SR.Get(SRID.SynthesizerSetVoiceNoMatch));
			}
			VoiceSynthesizer.Voice = engine;
		}

		public Prompt SpeakAsync(string textToSpeak)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			Prompt prompt = new Prompt(textToSpeak, SynthesisTextFormat.Text);
			SpeakAsync(prompt);
			return prompt;
		}

		public void SpeakAsync(Prompt prompt)
		{
			Helpers.ThrowIfNull(prompt, "prompt");
			prompt.Synthesizer = this;
			VoiceSynthesizer.SpeakAsync(prompt);
		}

		public Prompt SpeakSsmlAsync(string textToSpeak)
		{
			Helpers.ThrowIfNull(textToSpeak, "textToSpeak");
			Prompt prompt = new Prompt(textToSpeak, SynthesisTextFormat.Ssml);
			SpeakAsync(prompt);
			return prompt;
		}

		public Prompt SpeakAsync(PromptBuilder promptBuilder)
		{
			Helpers.ThrowIfNull(promptBuilder, "promptBuilder");
			Prompt prompt = new Prompt(promptBuilder);
			SpeakAsync(prompt);
			return prompt;
		}

		public void Speak(string textToSpeak)
		{
			Speak(new Prompt(textToSpeak, SynthesisTextFormat.Text));
		}

		public void Speak(Prompt prompt)
		{
			Helpers.ThrowIfNull(prompt, "prompt");
			if (State == SynthesizerState.Paused)
			{
				throw new InvalidOperationException(SR.Get(SRID.SynthesizerSyncSpeakWhilePaused));
			}
			prompt.Synthesizer = this;
			prompt._syncSpeak = true;
			VoiceSynthesizer.Speak(prompt);
		}

		public void Speak(PromptBuilder promptBuilder)
		{
			Speak(new Prompt(promptBuilder));
		}

		public void SpeakSsml(string textToSpeak)
		{
			Speak(new Prompt(textToSpeak, SynthesisTextFormat.Ssml));
		}

		public void Pause()
		{
			if (!paused)
			{
				VoiceSynthesizer.Pause();
				paused = true;
			}
		}

		public void Resume()
		{
			if (paused)
			{
				VoiceSynthesizer.Resume();
				paused = false;
			}
		}

		public void SpeakAsyncCancel(Prompt prompt)
		{
			Helpers.ThrowIfNull(prompt, "prompt");
			VoiceSynthesizer.Abort(prompt);
		}

		public void SpeakAsyncCancelAll()
		{
			VoiceSynthesizer.Abort();
		}

		public void SetOutputToWaveFile(string path)
		{
			Helpers.ThrowIfEmptyOrNull(path, "path");
			SetOutputToNull();
			SetOutputStream(new FileStream(path, FileMode.Create, FileAccess.Write), null, headerInfo: true, closeStreamOnExit: true);
		}

		public void SetOutputToWaveFile(string path, SpeechAudioFormatInfo formatInfo)
		{
			Helpers.ThrowIfEmptyOrNull(path, "path");
			Helpers.ThrowIfNull(formatInfo, "formatInfo");
			SetOutputToNull();
			SetOutputStream(new FileStream(path, FileMode.Create, FileAccess.Write), formatInfo, headerInfo: true, closeStreamOnExit: true);
		}

		public void SetOutputToWaveStream(Stream audioDestination)
		{
			Helpers.ThrowIfNull(audioDestination, "audioDestination");
			SetOutputStream(audioDestination, null, headerInfo: true, closeStreamOnExit: false);
		}

		public void SetOutputToAudioStream(Stream audioDestination, SpeechAudioFormatInfo formatInfo)
		{
			Helpers.ThrowIfNull(audioDestination, "audioDestination");
			Helpers.ThrowIfNull(formatInfo, "formatInfo");
			SetOutputStream(audioDestination, formatInfo, headerInfo: false, closeStreamOnExit: false);
		}

		public void SetOutputToDefaultAudioDevice()
		{
			SetOutputStream(null, null, headerInfo: true, closeStreamOnExit: false);
		}

		public void SetOutputToNull()
		{
			if (_outputStream != Stream.Null)
			{
				VoiceSynthesizer.SetOutput(Stream.Null, null, headerInfo: true);
			}
			if (_outputStream != null && _closeStreamOnExit)
			{
				_outputStream.Close();
			}
			_outputStream = Stream.Null;
		}

		public Prompt GetCurrentlySpokenPrompt()
		{
			return VoiceSynthesizer.Prompt;
		}

		public ReadOnlyCollection<InstalledVoice> GetInstalledVoices()
		{
			return VoiceSynthesizer.GetInstalledVoices(null);
		}

		public ReadOnlyCollection<InstalledVoice> GetInstalledVoices(CultureInfo culture)
		{
			Helpers.ThrowIfNull(culture, "culture");
			if (culture.Equals(CultureInfo.InvariantCulture))
			{
				throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture");
			}
			return VoiceSynthesizer.GetInstalledVoices(culture);
		}

		public void AddLexicon(Uri uri, string mediaType)
		{
			Helpers.ThrowIfNull(uri, "uri");
			VoiceSynthesizer.AddLexicon(uri, mediaType);
		}

		public void RemoveLexicon(Uri uri)
		{
			Helpers.ThrowIfNull(uri, "uri");
			VoiceSynthesizer.RemoveLexicon(uri);
		}

		private void SetOutputStream(Stream stream, SpeechAudioFormatInfo formatInfo, bool headerInfo, bool closeStreamOnExit)
		{
			SetOutputToNull();
			_outputStream = stream;
			_closeStreamOnExit = closeStreamOnExit;
			VoiceSynthesizer.SetOutput(stream, formatInfo, headerInfo);
		}

		private void Dispose(bool disposing)
		{
			if (!_isDisposed && disposing && _voiceSynthesis != null)
			{
				_isDisposed = true;
				SpeakAsyncCancelAll();
				if (_outputStream != null)
				{
					if (_closeStreamOnExit)
					{
						_outputStream.Close();
					}
					else
					{
						_outputStream.Flush();
					}
					_outputStream = null;
				}
			}
			if (_voiceSynthesis != null)
			{
				_voiceSynthesis.Dispose();
				_voiceSynthesis = null;
			}
			_isDisposed = true;
		}
	}
	public enum SynthesizerState
	{
		Ready,
		Speaking,
		Paused
	}
	[Flags]
	public enum SynthesizerEmphasis
	{
		Stressed = 1,
		Emphasized = 2
	}
	public class SpeakCompletedEventArgs : PromptEventArgs
	{
		internal SpeakCompletedEventArgs(Prompt prompt)
			: base(prompt)
		{
		}
	}
	public class SpeakProgressEventArgs : PromptEventArgs
	{
		private TimeSpan _audioPosition;

		private int _iWordPos;

		private int _cWordLen;

		private string _word;

		public TimeSpan AudioPosition => _audioPosition;

		public int CharacterPosition => _iWordPos;

		public int CharacterCount
		{
			get
			{
				return _cWordLen;
			}
			internal set
			{
				_cWordLen = value;
			}
		}

		public string Text
		{
			get
			{
				return _word;
			}
			internal set
			{
				_word = value;
			}
		}

		internal SpeakProgressEventArgs(Prompt prompt, TimeSpan audioPosition, int iWordPos, int cWordLen)
			: base(prompt)
		{
			_audioPosition = audioPosition;
			_iWordPos = iWordPos;
			_cWordLen = cWordLen;
		}
	}
	public class StateChangedEventArgs : EventArgs
	{
		private SynthesizerState _state;

		private SynthesizerState _previousState;

		public SynthesizerState State => _state;

		public SynthesizerState PreviousState => _previousState;

		internal StateChangedEventArgs(SynthesizerState state, SynthesizerState previousState)
		{
			_state = state;
			_previousState = previousState;
		}
	}
	[Serializable]
	[DebuggerDisplay("{(_name != null ? \"'\" + _name + \"' \" : \"\") +  (_culture != null ? \" '\" + _culture.ToString () + \"' \" : \"\") + (_gender != VoiceGender.NotSet ? \" '\" + _gender.ToString () + \"' \" : \"\") + (_age != VoiceAge.NotSet ? \" '\" + _age.ToString () + \"' \" : \"\") + (_variant > 0 ? \" \" + _variant.ToString () : \"\")}")]
	public class VoiceInfo
	{
		private string _name;

		private CultureInfo _culture;

		private VoiceGender _gender;

		private VoiceAge _age;

		private int _variant = -1;

		[NonSerialized]
		private string _id;

		[NonSerialized]
		private string _registryKeyPath;

		[NonSerialized]
		private string _assemblyName;

		[NonSerialized]
		private string _clsid;

		[NonSerialized]
		private string _description;

		[NonSerialized]
		private ReadOnlyDictionary<string, string> _attributes;

		[NonSerialized]
		private ReadOnlyCollection<SpeechAudioFormatInfo> _audioFormats;

		public VoiceGender Gender => _gender;

		public VoiceAge Age => _age;

		public string Name => _name;

		public CultureInfo Culture => _culture;

		public string Id => _id;

		public string Description
		{
			get
			{
				if (_description == null)
				{
					return string.Empty;
				}
				return _description;
			}
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public ReadOnlyCollection<SpeechAudioFormatInfo> SupportedAudioFormats => _audioFormats;

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public IDictionary<string, string> AdditionalInfo
		{
			get
			{
				if (_attributes == null)
				{
					_attributes = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(0));
				}
				return _attributes;
			}
		}

		internal int Variant => _variant;

		internal string AssemblyName => _assemblyName;

		internal string Clsid => _clsid;

		internal string RegistryKeyPath => _registryKeyPath;

		internal VoiceInfo(string name)
		{
			Helpers.ThrowIfEmptyOrNull(name, "name");
			_name = name;
		}

		internal VoiceInfo(CultureInfo culture)
		{
			Helpers.ThrowIfNull(culture, "culture");
			if (culture.Equals(CultureInfo.InvariantCulture))
			{
				throw new ArgumentException(SR.Get(SRID.InvariantCultureInfo), "culture");
			}
			_culture = culture;
		}

		internal VoiceInfo(ObjectToken token)
		{
			_registryKeyPath = token._sKeyId;
			_id = token.Name;
			_description = token.Description;
			_name = token.TokenName();
			SsmlParserHelpers.TryConvertAge(token.Age.ToLowerInvariant(), out _age);
			SsmlParserHelpers.TryConvertGender(token.Gender.ToLowerInvariant(), out _gender);
			if (token.Attributes.TryGetString("Language", out var value))
			{
				_culture = SapiAttributeParser.GetCultureInfoFromLanguageString(value);
			}
			if (token.TryGetString("Assembly", out var value2))
			{
				_assemblyName = value2;
			}
			if (token.TryGetString("CLSID", out var value3))
			{
				_clsid = value3;
			}
			if (token.Attributes != null)
			{
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				string[] valueNames = token.Attributes.GetValueNames();
				foreach (string text in valueNames)
				{
					if (token.Attributes.TryGetString(text, out var value4))
					{
						dictionary.Add(text, value4);
					}
				}
				_attributes = new ReadOnlyDictionary<string, string>(dictionary);
			}
			if (token.Attributes != null && token.Attributes.TryGetString("AudioFormats", out var value5))
			{
				_audioFormats = new ReadOnlyCollection<SpeechAudioFormatInfo>(SapiAttributeParser.GetAudioFormatsFromString(value5));
			}
			else
			{
				_audioFormats = new ReadOnlyCollection<SpeechAudioFormatInfo>(new List<SpeechAudioFormatInfo>());
			}
		}

		internal VoiceInfo(VoiceGender gender)
		{
			_gender = gender;
		}

		internal VoiceInfo(VoiceGender gender, VoiceAge age)
		{
			_gender = gender;
			_age = age;
		}

		internal VoiceInfo(VoiceGender gender, VoiceAge age, int voiceAlternate)
		{
			if (voiceAlternate < 0)
			{
				throw new ArgumentOutOfRangeException("voiceAlternate", SR.Get(SRID.PromptBuilderInvalidVariant));
			}
			_gender = gender;
			_age = age;
			_variant = voiceAlternate + 1;
		}

		public override bool Equals(object obj)
		{
			if (obj is VoiceInfo voiceInfo && _name == voiceInfo._name && (_age == voiceInfo._age || _age == VoiceAge.NotSet || voiceInfo._age == VoiceAge.NotSet) && (_gender == voiceInfo._gender || _gender == VoiceGender.NotSet || voiceInfo._gender == VoiceGender.NotSet))
			{
				if (_culture != null && voiceInfo._culture != null)
				{
					return _culture.Equals(voiceInfo._culture);
				}
				return true;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return _name.GetHashCode();
		}

		internal static bool ValidateGender(VoiceGender gender)
		{
			if (gender != VoiceGender.Female && gender != VoiceGender.Male && gender != VoiceGender.Neutral)
			{
				return gender == VoiceGender.NotSet;
			}
			return true;
		}

		internal static bool ValidateAge(VoiceAge age)
		{
			if (age != VoiceAge.Adult && age != VoiceAge.Child && age != 0 && age != VoiceAge.Senior)
			{
				return age == VoiceAge.Teen;
			}
			return true;
		}
	}
	public class VoiceChangeEventArgs : PromptEventArgs
	{
		private VoiceInfo _voice;

		public VoiceInfo Voice => _voice;

		internal VoiceChangeEventArgs(Prompt prompt, VoiceInfo voice)
			: base(prompt)
		{
			_voice = voice;
		}
	}
	public class VisemeReachedEventArgs : PromptEventArgs
	{
		private int _currentViseme;

		private TimeSpan _audioPosition;

		private TimeSpan _duration;

		private SynthesizerEmphasis _emphasis;

		private int _nextViseme;

		public int Viseme => _currentViseme;

		public TimeSpan AudioPosition => _audioPosition;

		public TimeSpan Duration => _duration;

		public SynthesizerEmphasis Emphasis => _emphasis;

		public int NextViseme => _nextViseme;

		internal VisemeReachedEventArgs(Prompt speakPrompt, int currentViseme, TimeSpan audioPosition, TimeSpan duration, SynthesizerEmphasis emphasis, int nextViseme)
			: base(speakPrompt)
		{
			_currentViseme = currentViseme;
			_audioPosition = audioPosition;
			_duration = duration;
			_emphasis = emphasis;
			_nextViseme = nextViseme;
		}
	}
	public class PhonemeReachedEventArgs : PromptEventArgs
	{
		private string _currentPhoneme;

		private TimeSpan _audioPosition;

		private TimeSpan _duration;

		private SynthesizerEmphasis _emphasis;

		private string _nextPhoneme;

		public string Phoneme => _currentPhoneme;

		public TimeSpan AudioPosition => _audioPosition;

		public TimeSpan Duration => _duration;

		public SynthesizerEmphasis Emphasis => _emphasis;

		public string NextPhoneme => _nextPhoneme;

		internal PhonemeReachedEventArgs(Prompt prompt, string currentPhoneme, TimeSpan audioPosition, TimeSpan duration, SynthesizerEmphasis emphasis, string nextPhoneme)
			: base(prompt)
		{
			_currentPhoneme = currentPhoneme;
			_audioPosition = audioPosition;
			_duration = duration;
			_emphasis = emphasis;
			_nextPhoneme = nextPhoneme;
		}
	}
}
namespace System.Speech.Synthesis.TtsEngine
{
	[ComImport]
	[Guid("A74D7C8E-4CC5-4F2F-A6EB-804DEE18500E")]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	internal interface ITtsEngine
	{
		[PreserveSig]
		void Speak(SPEAKFLAGS dwSpeakFlags, ref Guid rguidFormatId, IntPtr pWaveFormatEx, IntPtr pTextFragList, IntPtr pOutputSite);

		[PreserveSig]
		void GetOutputFormat(ref Guid pTargetFmtId, IntPtr pTargetWaveFormatEx, out Guid pOutputFormatId, out IntPtr ppCoMemOutputWaveFormatEx);
	}
	[StructLayout(LayoutKind.Sequential)]
	internal class SPVTEXTFRAG
	{
		public IntPtr pNext;

		public SPVSTATE State;

		public IntPtr pTextStart;

		public int ulTextLen;

		public int ulTextSrcOffset;

		public GCHandle gcText;

		public GCHandle gcNext;

		public GCHandle gcPhoneme;

		public GCHandle gcSayAsCategory;
	}
	internal enum SPVSKIPTYPE
	{
		SPVST_SENTENCE = 1
	}
	[ComConversionLoss]
	[TypeLibType(16)]
	internal struct SPVSTATE
	{
		public SPVACTIONS eAction;

		public short LangID;

		public short wReserved;

		public int EmphAdj;

		public int RateAdj;

		public int Volume;

		public SPVPITCH PitchAdj;

		public int SilenceMSecs;

		public IntPtr pPhoneIds;

		public SPPARTOFSPEECH ePartOfSpeech;

		public SPVCONTEXT Context;
	}
	[TypeLibType(16)]
	internal struct SPVCONTEXT
	{
		public IntPtr pCategory;

		public IntPtr pBefore;

		public IntPtr pAfter;
	}
	[TypeLibType(16)]
	internal struct SPVPITCH
	{
		public int MiddleAdj;

		public int RangeAdj;
	}
	internal static class SAPIGuids
	{
		internal static readonly Guid SPDFID_WaveFormatEx = new Guid("C31ADBAE-527F-4ff5-A230-F62BB61FF70C");
	}
	[Flags]
	internal enum SPEAKFLAGS
	{
		SPF_DEFAULT = 0,
		SPF_ASYNC = 1,
		SPF_PURGEBEFORESPEAK = 2,
		SPF_IS_FILENAME = 4,
		SPF_IS_XML = 8,
		SPF_IS_NOT_XML = 0x10,
		SPF_PERSIST_XML = 0x20,
		SPF_NLP_SPEAK_PUNC = 0x40,
		SPF_PARSE_SAPI = 0x80,
		SPF_PARSE_SSML = 0x100
	}
	[Flags]
	internal enum SPVESACTIONS
	{
		SPVES_CONTINUE = 0,
		SPVES_ABORT = 1,
		SPVES_SKIP = 2,
		SPVES_RATE = 4,
		SPVES_VOLUME = 8
	}
	[TypeLibType(16)]
	internal enum SPVACTIONS
	{
		SPVA_Speak,
		SPVA_Silence,
		SPVA_Pronounce,
		SPVA_Bookmark,
		SPVA_SpellOut,
		SPVA_Section,
		SPVA_ParseUnknownTag
	}
	[TypeLibType(16)]
	internal enum SPPARTOFSPEECH
	{
		SPPS_NotOverriden = -1,
		SPPS_Unknown = 0,
		SPPS_Noun = 4096,
		SPPS_Verb = 8192,
		SPPS_Modifier = 12288,
		SPPS_Function = 16384,
		SPPS_Interjection = 20480,
		SPPS_SuppressWord = 61440
	}
	public abstract class TtsEngineSsml
	{
		protected TtsEngineSsml(string registryKey)
		{
		}

		public abstract IntPtr GetOutputFormat(SpeakOutputFormat speakOutputFormat, IntPtr targetWaveFormat);

		public abstract void AddLexicon(Uri uri, string mediaType, ITtsEngineSite site);

		public abstract void RemoveLexicon(Uri uri, ITtsEngineSite site);

		public abstract void Speak(TextFragment[] fragment, IntPtr waveHeader, ITtsEngineSite site);
	}
	[ImmutableObject(true)]
	public struct SpeechEventInfo : IEquatable<SpeechEventInfo>
	{
		private short _eventId;

		private short _parameterType;

		private int _param1;

		private IntPtr _param2;

		public short EventId
		{
			get
			{
				return _eventId;
			}
			internal set
			{
				_eventId = value;
			}
		}

		public short ParameterType
		{
			get
			{
				return _parameterType;
			}
			internal set
			{
				_parameterType = value;
			}
		}

		public int Param1
		{
			get
			{
				return _param1;
			}
			internal set
			{
				_param1 = value;
			}
		}

		public IntPtr Param2
		{
			get
			{
				return _param2;
			}
			internal set
			{
				_param2 = value;
			}
		}

		public SpeechEventInfo(short eventId, short parameterType, int param1, IntPtr param2)
		{
			_eventId = eventId;
			_parameterType = parameterType;
			_param1 = param1;
			_param2 = param2;
		}

		public static bool operator ==(SpeechEventInfo event1, SpeechEventInfo event2)
		{
			if (event1.EventId == event2.EventId && event1.ParameterType == event2.ParameterType && event1.Param1 == event2.Param1)
			{
				return event1.Param2 == event2.Param2;
			}
			return false;
		}

		public static bool operator !=(SpeechEventInfo event1, SpeechEventInfo event2)
		{
			return !(event1 == event2);
		}

		public bool Equals(SpeechEventInfo other)
		{
			return this == other;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is SpeechEventInfo))
			{
				return false;
			}
			return Equals((SpeechEventInfo)obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
	public interface ITtsEngineSite
	{
		int EventInterest { get; }

		int Actions { get; }

		int Rate { get; }

		int Volume { get; }

		void AddEvents(SpeechEventInfo[] events, int count);

		int Write(IntPtr data, int count);

		SkipInfo GetSkipInfo();

		void CompleteSkip(int skipped);

		Stream LoadResource(Uri uri, string mediaType);
	}
	public class SkipInfo
	{
		private int _type;

		private int _count;

		public int Type
		{
			get
			{
				return _type;
			}
			set
			{
				_type = value;
			}
		}

		public int Count
		{
			get
			{
				return _count;
			}
			set
			{
				_count = value;
			}
		}

		internal SkipInfo(int type, int count)
		{
			_type = type;
			_count = count;
		}

		public SkipInfo()
		{
		}
	}
	[StructLayout(LayoutKind.Sequential)]
	public class TextFragment
	{
		private FragmentState _state;

		[MarshalAs(UnmanagedType.LPWStr)]
		private string _textToSpeak = string.Empty;

		private int _textOffset;

		private int _textLength;

		public FragmentState State
		{
			get
			{
				return _state;
			}
			set
			{
				_state = value;
			}
		}

		public string TextToSpeak
		{
			get
			{
				return _textToSpeak;
			}
			set
			{
				Helpers.ThrowIfEmptyOrNull(value, "value");
				_textToSpeak = value;
			}
		}

		public int TextOffset
		{
			get
			{
				return _textOffset;
			}
			set
			{
				_textOffset = value;
			}
		}

		public int TextLength
		{
			get
			{
				return _textLength;
			}
			set
			{
				_textLength = value;
			}
		}

		public TextFragment()
		{
		}

		internal TextFragment(FragmentState fragState)
			: this(fragState, null, null, 0, 0)
		{
		}

		internal TextFragment(FragmentState fragState, string textToSpeak)
			: this(fragState, textToSpeak, textToSpeak, 0, textToSpeak.Length)
		{
		}

		internal TextFragment(FragmentState fragState, string textToSpeak, string textFrag, int offset, int length)
		{
			if (fragState.Action == TtsEngineAction.Speak || fragState.Action == TtsEngineAction.Pronounce)
			{
				textFrag = textToSpeak;
			}
			if (!string.IsNullOrEmpty(textFrag))
			{
				TextToSpeak = textFrag;
			}
			State = fragState;
			TextOffset = offset;
			TextLength = length;
		}
	}
	[ImmutableObject(true)]
	public struct FragmentState : IEquatable<FragmentState>
	{
		private TtsEngineAction _action;

		private int _langId;

		private int _emphasis;

		private int _duration;

		private SayAs _sayAs;

		private Prosody _prosody;

		private char[] _phoneme;

		public TtsEngineAction Action
		{
			get
			{
				return _action;
			}
			internal set
			{
				_action = value;
			}
		}

		public int LangId
		{
			get
			{
				return _langId;
			}
			internal set
			{
				_langId = value;
			}
		}

		public int Emphasis
		{
			get
			{
				return _emphasis;
			}
			internal set
			{
				_emphasis = value;
			}
		}

		public int Duration
		{
			get
			{
				return _duration;
			}
			internal set
			{
				_duration = value;
			}
		}

		public SayAs SayAs
		{
			get
			{
				return _sayAs;
			}
			internal set
			{
				Helpers.ThrowIfNull(value, "value");
				_sayAs = value;
			}
		}

		public Prosody Prosody
		{
			get
			{
				return _prosody;
			}
			internal set
			{
				Helpers.ThrowIfNull(value, "value");
				_prosody = value;
			}
		}

		public char[] Phoneme
		{
			get
			{
				return _phoneme;
			}
			internal set
			{
				Helpers.ThrowIfNull(value, "value");
				_phoneme = value;
			}
		}

		public FragmentState(TtsEngineAction action, int langId, int emphasis, int duration, SayAs sayAs, Prosody prosody, char[] phonemes)
		{
			_action = action;
			_langId = langId;
			_emphasis = emphasis;
			_duration = duration;
			_sayAs = sayAs;
			_prosody = prosody;
			_phoneme = phonemes;
		}

		public static bool operator ==(FragmentState state1, FragmentState state2)
		{
			if (state1.Action == state2.Action && state1.LangId == state2.LangId && state1.Emphasis == state2.Emphasis && state1.Duration == state2.Duration && state1.SayAs == state2.SayAs && state1.Prosody == state2.Prosody)
			{
				return object.Equals(state1.Phoneme, state2.Phoneme);
			}
			return false;
		}

		public static bool operator !=(FragmentState state1, FragmentState state2)
		{
			return !(state1 == state2);
		}

		public bool Equals(FragmentState other)
		{
			return this == other;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is FragmentState))
			{
				return false;
			}
			return Equals((FragmentState)obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
	[StructLayout(LayoutKind.Sequential)]
	public class Prosody
	{
		internal ProsodyNumber _pitch;

		internal ProsodyNumber _range;

		internal ProsodyNumber _rate;

		internal int _duration;

		internal ProsodyNumber _volume;

		internal ContourPoint[] _contourPoints;

		public ProsodyNumber Pitch
		{
			get
			{
				return _pitch;
			}
			set
			{
				_pitch = value;
			}
		}

		public ProsodyNumber Range
		{
			get
			{
				return _range;
			}
			set
			{
				_range = value;
			}
		}

		public ProsodyNumber Rate
		{
			get
			{
				return _rate;
			}
			set
			{
				_rate = value;
			}
		}

		public int Duration
		{
			get
			{
				return _duration;
			}
			set
			{
				_duration = value;
			}
		}

		public ProsodyNumber Volume
		{
			get
			{
				return _volume;
			}
			set
			{
				_volume = value;
			}
		}

		public ContourPoint[] GetContourPoints()
		{
			return _contourPoints;
		}

		public void SetContourPoints(ContourPoint[] points)
		{
			Helpers.ThrowIfNull(points, "points");
			_contourPoints = (ContourPoint[])points.Clone();
		}

		public Prosody()
		{
			Pitch = new ProsodyNumber(0);
			Range = new ProsodyNumber(0);
			Rate = new ProsodyNumber(0);
			Volume = new ProsodyNumber(-1);
		}

		internal Prosody Clone()
		{
			Prosody prosody = new Prosody();
			prosody._pitch = _pitch;
			prosody._range = _range;
			prosody._rate = _rate;
			prosody._duration = _duration;
			prosody._volume = _volume;
			return prosody;
		}
	}
	[ImmutableObject(true)]
	public struct ContourPoint : IEquatable<ContourPoint>
	{
		private float _start;

		private float _change;

		private ContourPointChangeType _changeType;

		public float Start => _start;

		public float Change => _change;

		public ContourPointChangeType ChangeType => _changeType;

		public ContourPoint(float start, float change, ContourPointChangeType changeType)
		{
			_start = start;
			_change = change;
			_changeType = changeType;
		}

		public static bool operator ==(ContourPoint point1, ContourPoint point2)
		{
			if (point1.Start.Equals(point2.Start) && point1.Change.Equals(point2.Change))
			{
				return point1.ChangeType.Equals(point2.ChangeType);
			}
			return false;
		}

		public static bool operator !=(ContourPoint point1, ContourPoint point2)
		{
			return !(point1 == point2);
		}

		public bool Equals(ContourPoint other)
		{
			return this == other;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is ContourPoint))
			{
				return false;
			}
			return Equals((ContourPoint)obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
	[ImmutableObject(true)]
	public struct ProsodyNumber : IEquatable<ProsodyNumber>
	{
		public const int AbsoluteNumber = int.MaxValue;

		private int _ssmlAttributeId;

		private bool _isPercent;

		private float _number;

		private ProsodyUnit _unit;

		public int SsmlAttributeId
		{
			get
			{
				return _ssmlAttributeId;
			}
			internal set
			{
				_ssmlAttributeId = value;
			}
		}

		public bool IsNumberPercent
		{
			get
			{
				return _isPercent;
			}
			internal set
			{
				_isPercent = value;
			}
		}

		public float Number
		{
			get
			{
				return _number;
			}
			internal set
			{
				_number = value;
			}
		}

		public ProsodyUnit Unit
		{
			get
			{
				return _unit;
			}
			internal set
			{
				_unit = value;
			}
		}

		public ProsodyNumber(int ssmlAttributeId)
		{
			_ssmlAttributeId = ssmlAttributeId;
			_number = 1f;
			_isPercent = true;
			_unit = ProsodyUnit.Default;
		}

		public ProsodyNumber(float number)
		{
			_ssmlAttributeId = int.MaxValue;
			_number = number;
			_isPercent = false;
			_unit = ProsodyUnit.Default;
		}

		public static bool operator ==(ProsodyNumber prosodyNumber1, ProsodyNumber prosodyNumber2)
		{
			if (prosodyNumber1._ssmlAttributeId == prosodyNumber2._ssmlAttributeId && prosodyNumber1.Number.Equals(prosodyNumber2.Number) && prosodyNumber1.IsNumberPercent == prosodyNumber2.IsNumberPercent)
			{
				return prosodyNumber1.Unit == prosodyNumber2.Unit;
			}
			return false;
		}

		public static bool operator !=(ProsodyNumber prosodyNumber1, ProsodyNumber prosodyNumber2)
		{
			return !(prosodyNumber1 == prosodyNumber2);
		}

		public bool Equals(ProsodyNumber other)
		{
			return this == other;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is ProsodyNumber))
			{
				return false;
			}
			return Equals((ProsodyNumber)obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
	[StructLayout(LayoutKind.Sequential)]
	public class SayAs
	{
		[MarshalAs(UnmanagedType.LPWStr)]
		private string _interpretAs;

		[MarshalAs(UnmanagedType.LPWStr)]
		private string _format;

		[MarshalAs(UnmanagedType.LPWStr)]
		private string _detail;

		public string InterpretAs
		{
			get
			{
				return _interpretAs;
			}
			set
			{
				Helpers.ThrowIfEmptyOrNull(value, "value");
				_interpretAs = value;
			}
		}

		public string Format
		{
			get
			{
				return _format;
			}
			set
			{
				Helpers.ThrowIfEmptyOrNull(value, "value");
				_format = value;
			}
		}

		public string Detail
		{
			get
			{
				return _detail;
			}
			set
			{
				Helpers.ThrowIfEmptyOrNull(value, "value");
				_detail = value;
			}
		}
	}
	public enum TtsEngineAction
	{
		Speak,
		Silence,
		Pronounce,
		Bookmark,
		SpellOut,
		StartSentence,
		StartParagraph,
		ParseUnknownTag
	}
	public enum EmphasisWord
	{
		Default,
		Strong,
		Moderate,
		None,
		Reduced
	}
	public enum EmphasisBreak
	{
		None = -1,
		ExtraWeak = -2,
		Weak = -3,
		Medium = -4,
		Strong = -5,
		ExtraStrong = -6,
		Default = -7
	}
	public enum ProsodyPitch
	{
		Default,
		ExtraLow,
		Low,
		Medium,
		High,
		ExtraHigh
	}
	public enum ProsodyRange
	{
		Default,
		ExtraLow,
		Low,
		Medium,
		High,
		ExtraHigh
	}
	public enum ProsodyRate
	{
		Default,
		ExtraSlow,
		Slow,
		Medium,
		Fast,
		ExtraFast
	}
	public enum ProsodyVolume
	{
		Default = -1,
		Silent = -2,
		ExtraSoft = -3,
		Soft = -4,
		Medium = -5,
		Loud = -6,
		ExtraLoud = -7
	}
	public enum ProsodyUnit
	{
		Default,
		Hz,
		Semitone
	}
	public enum TtsEventId
	{
		StartInputStream = 1,
		EndInputStream,
		VoiceChange,
		Bookmark,
		WordBoundary,
		Phoneme,
		SentenceBoundary,
		Viseme,
		AudioLevel
	}
	public enum EventParameterType
	{
		Undefined,
		Token,
		Object,
		Pointer,
		String
	}
	public enum SpeakOutputFormat
	{
		WaveFormat,
		Text
	}
	public enum ContourPointChangeType
	{
		Hz,
		Percentage
	}
	[ComImport]
	[Guid("2D0FA0DB-AEA2-4AE2-9F8A-7AFC7794E56B")]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	internal interface ITtsEngineSsml
	{
		void GetOutputFormat(SpeakOutputFormat speakOutputFormat, IntPtr targetWaveFormat, out IntPtr waveHeader);

		void AddLexicon(string location, string mediaType, IntPtr site);

		void RemoveLexicon(string location, IntPtr site);

		void Speak(IntPtr fragments, int count, IntPtr waveHeader, IntPtr site);
	}
	internal struct TextFragmentInterop
	{
		internal FragmentStateInterop _state;

		[MarshalAs(UnmanagedType.LPWStr)]
		internal string _textToSpeak;

		internal int _textOffset;

		internal int _textLength;

		internal static IntPtr FragmentToPtr(List<TextFragment> textFragments, Collection<IntPtr> memoryBlocks)
		{
			TextFragmentInterop textFragmentInterop = default(TextFragmentInterop);
			int count = textFragments.Count;
			int num = Marshal.SizeOf((object)textFragmentInterop);
			IntPtr intPtr = Marshal.AllocCoTaskMem(num * count);
			memoryBlocks.Add(intPtr);
			for (int i = 0; i < count; i++)
			{
				textFragmentInterop._state.FragmentStateToPtr(textFragments[i].State, memoryBlocks);
				textFragmentInterop._textToSpeak = textFragments[i].TextToSpeak;
				textFragmentInterop._textOffset = textFragments[i].TextOffset;
				textFragmentInterop._textLength = textFragments[i].TextLength;
				Marshal.StructureToPtr((object)textFragmentInterop, (IntPtr)((long)intPtr + i * num), fDeleteOld: false);
			}
			return intPtr;
		}
	}
	internal struct FragmentStateInterop
	{
		internal TtsEngineAction _action;

		internal int _langId;

		internal int _emphasis;

		internal int _duration;

		internal IntPtr _sayAs;

		internal IntPtr _prosody;

		internal IntPtr _phoneme;

		internal void FragmentStateToPtr(FragmentState state, Collection<IntPtr> memoryBlocks)
		{
			_action = state.Action;
			_langId = state.LangId;
			_emphasis = state.Emphasis;
			_duration = state.Duration;
			if (state.SayAs != null)
			{
				_sayAs = Marshal.AllocCoTaskMem(Marshal.SizeOf((object)state.SayAs));
				memoryBlocks.Add(_sayAs);
				Marshal.StructureToPtr((object)state.SayAs, _sayAs, fDeleteOld: false);
			}
			else
			{
				_sayAs = IntPtr.Zero;
			}
			if (state.Phoneme != null)
			{
				short[] array = new short[state.Phoneme.Length + 1];
				for (uint num = 0u; num < state.Phoneme.Length; num++)
				{
					array[num] = (short)state.Phoneme[num];
				}
				array[state.Phoneme.Length] = 0;
				int num2 = Marshal.SizeOf((object)array[0]);
				_phoneme = Marshal.AllocCoTaskMem(num2 * array.Length);
				memoryBlocks.Add(_phoneme);
				for (uint num3 = 0u; num3 < array.Length; num3++)
				{
					Marshal.Copy(array, 0, _phoneme, array.Length);
				}
			}
			else
			{
				_phoneme = IntPtr.Zero;
			}
			_prosody = ProsodyInterop.ProsodyToPtr(state.Prosody, memoryBlocks);
		}
	}
	internal struct ProsodyInterop
	{
		internal ProsodyNumber _pitch;

		internal ProsodyNumber _range;

		internal ProsodyNumber _rate;

		internal int _duration;

		internal ProsodyNumber _volume;

		internal IntPtr _contourPoints;

		internal static IntPtr ProsodyToPtr(Prosody prosody, Collection<IntPtr> memoryBlocks)
		{
			if (prosody == null)
			{
				return IntPtr.Zero;
			}
			ProsodyInterop prosodyInterop = default(ProsodyInterop);
			prosodyInterop._pitch = prosody.Pitch;
			prosodyInterop._range = prosody.Range;
			prosodyInterop._rate = prosody.Rate;
			prosodyInterop._duration = prosody.Duration;
			prosodyInterop._volume = prosody.Volume;
			ContourPoint[] contourPoints = prosody.GetContourPoints();
			if (contourPoints != null)
			{
				int num = Marshal.SizeOf((object)contourPoints[0]);
				prosodyInterop._contourPoints = Marshal.AllocCoTaskMem(contourPoints.Length * num);
				memoryBlocks.Add(prosodyInterop._contourPoints);
				for (uint num2 = 0u; num2 < contourPoints.Length; num2++)
				{
					Marshal.StructureToPtr((object)contourPoints[num2], (IntPtr)((long)prosodyInterop._contourPoints + num * num2), fDeleteOld: false);
				}
			}
			else
			{
				prosodyInterop._contourPoints = IntPtr.Zero;
			}
			IntPtr intPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf((object)prosodyInterop));
			memoryBlocks.Add(intPtr);
			Marshal.StructureToPtr((object)prosodyInterop, intPtr, fDeleteOld: false);
			return intPtr;
		}
	}
}
namespace System.Speech.Recognition
{
	[DebuggerDisplay("Grammar: {(_uri != null ? \"uri=\" + _uri.ToString () + \" \" : \"\") + \"rule=\" + _ruleName }")]
	public class Grammar
	{
		private struct NameValuePair
		{
			internal string _name;

			internal string _value;
		}

		internal GrammarOptions _semanticTag;

		internal AppDomain _appDomain;

		internal AppDomainGrammarProxy _proxy;

		internal ScriptRef[] _scripts;

		private byte[] _cfgData;

		private Stream _appStream;

		private bool _isSrgsDocument;

		private SrgsDocument _srgsDocument;

		private GrammarBuilder _grammarBuilder;

		private IRecognizerInternal _recognizer;

		private GrammarState _grammarState;

		private Exception _loadException;

		private Uri _uri;

		private Uri _baseUri;

		private string _ruleName;

		private string _resources;

		private object[] _parameters;

		private string _onInitParameters;

		private bool _enabled = true;

		private bool _isStg;

		private bool _sapi53Only;

		private uint _sapiGrammarId;

		private float _weight = 1f;

		private int _priority;

		private InternalGrammarData _internalData;

		private string _grammarName = string.Empty;

		private Collection<Grammar> _ruleRefs;

		private static ResourceLoader _resourceLoader = new ResourceLoader();

		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				if (_grammarState != 0 && _enabled != value)
				{
					_recognizer.SetGrammarState(this, value);
				}
				_enabled = value;
			}
		}

		public float Weight
		{
			get
			{
				return _weight;
			}
			set
			{
				if ((double)value < 0.0 || (double)value > 1.0)
				{
					throw new ArgumentOutOfRangeException("value", SR.Get(SRID.GrammarInvalidWeight));
				}
				if (_grammarState != 0 && !_weight.Equals(value))
				{
					_recognizer.SetGrammarWeight(this, value);
				}
				_weight = value;
			}
		}

		public int Priority
		{
			get
			{
				return _priority;
			}
			set
			{
				if (value < -128 || value > 127)
				{
					throw new ArgumentOutOfRangeException("value", SR.Get(SRID.GrammarInvalidPriority));
				}
				if (_grammarState != 0 && _priority != value)
				{
					_recognizer.SetGrammarPriority(this, value);
				}
				_priority = value;
			}
		}

		public string Name
		{
			get
			{
				return _grammarName;
			}
			set
			{
				if (value == null)
				{
					value = string.Empty;
				}
				_grammarName = value;
			}
		}

		public string RuleName => _ruleName;

		public bool Loaded => _grammarState == GrammarState.Loaded;

		internal Uri Uri => _uri;

		internal IRecognizerInternal Recognizer
		{
			get
			{
				return _recognizer;
			}
			set
			{
				_recognizer = value;
			}
		}

		internal GrammarState State
		{
			get
			{
				return _grammarState;
			}
			set
			{
				switch (value)
				{
				case GrammarState.Unloaded:
					_loadException = null;
					_recognizer = null;
					if (_appDomain != null)
					{
						AppDomain.Unload(_appDomain);
						_appDomain = null;
					}
					break;
				default:
					_ = 3;
					break;
				case GrammarState.Loaded:
					break;
				}
				_grammarState = value;
			}
		}

		internal Exception LoadException
		{
			get
			{
				return _loadException;
			}
			set
			{
				_loadException = value;
			}
		}

		internal byte[] CfgData => _cfgData;

		internal Uri BaseUri => _baseUri;

		internal bool Sapi53Only => _sapi53Only;

		internal uint SapiGrammarId
		{
			get
			{
				return _sapiGrammarId;
			}
			set
			{
				_sapiGrammarId = value;
			}
		}

		protected internal virtual bool IsStg => _isStg;

		internal bool IsSrgsDocument => _isSrgsDocument;

		internal InternalGrammarData InternalData
		{
			get
			{
				return _internalData;
			}
			set
			{
				_internalData = value;
			}
		}

		protected string ResourceName
		{
			get
			{
				return _resources;
			}
			set
			{
				Helpers.ThrowIfEmptyOrNull(value, "value");
				_resources = value;
			}
		}

		public event EventHandler<SpeechRecognizedEventArgs> SpeechRecognized;

		internal Grammar(Uri uri, string ruleName, object[] parameters)
		{
			Helpers.ThrowIfNull(uri, "uri");
			_uri = uri;
			InitialGrammarLoad(ruleName, parameters, isImportedGrammar: false);
		}

		public Grammar(string path)
			: this(path, (string)null, (object[])null)
		{
		}

		public Grammar(string path, string ruleName)
			: this(path, ruleName, null)
		{
		}

		public Grammar(string path, string ruleName, object[] parameters)
		{
			try
			{
				_uri = new Uri(path, UriKind.Relative);
			}
			catch (UriFormatException innerException)
			{
				throw new ArgumentException(SR.Get(SRID.RecognizerGrammarNotFound), "path", innerException);
			}
			InitialGrammarLoad(ruleName, parameters, isImportedGrammar: false);
		}

		public Grammar(SrgsDocument srgsDocument)
			: this(srgsDocument, null, null, null)
		{
		}

		public Grammar(SrgsDocument srgsDocument, string ruleName)
			: this(srgsDocument, ruleName, null, null)
		{
		}

		public Grammar(SrgsDocument srgsDocument, string ruleName, object[] parameters)
			: this(srgsDocument, ruleName, null, parameters)
		{
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public Grammar(SrgsDocument srgsDocument, string ruleName, Uri baseUri)
			: this(srgsDocument, ruleName, baseUri, null)
		{
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public Grammar(SrgsDocument srgsDocument, string ruleName, Uri baseUri, object[] parameters)
		{
			Helpers.ThrowIfNull(srgsDocument, "srgsDocument");
			_srgsDocument = srgsDocument;
			_isSrgsDocument = srgsDocument != null;
			_baseUri = baseUri;
			InitialGrammarLoad(ruleName, parameters, isImportedGrammar: false);
		}

		public Grammar(Stream stream)
			: this(stream, null, null, null)
		{
		}

		public Grammar(Stream stream, string ruleName)
			: this(stream, ruleName, null, null)
		{
		}

		public Grammar(Stream stream, string ruleName, object[] parameters)
			: this(stream, ruleName, null, parameters)
		{
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public Grammar(Stream stream, string ruleName, Uri baseUri)
			: this(stream, ruleName, baseUri, null)
		{
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public Grammar(Stream stream, string ruleName, Uri baseUri, object[] parameters)
		{
			Helpers.ThrowIfNull(stream, "stream");
			if (!stream.CanRead)
			{
				throw new ArgumentException(SR.Get(SRID.StreamMustBeReadable), "stream");
			}
			_appStream = stream;
			_baseUri = baseUri;
			InitialGrammarLoad(ruleName, parameters, isImportedGrammar: false);
		}

		public Grammar(GrammarBuilder builder)
		{
			Helpers.ThrowIfNull(builder, "builder");
			_grammarBuilder = builder;
			InitialGrammarLoad(null, null, isImportedGrammar: false);
		}

		private Grammar(string onInitParameters, Stream stream, string ruleName)
		{
			_appStream = stream;
			_onInitParameters = onInitParameters;
			InitialGrammarLoad(ruleName, null, isImportedGrammar: true);
		}

		protected Grammar()
		{
		}

		protected void StgInit(object[] parameters)
		{
			_parameters = parameters;
			LoadAndCompileCfgData(isImportedGrammar: false, stgInit: true);
		}

		public static Grammar LoadLocalizedGrammarFromType(Type type, params object[] onInitParameters)
		{
			Helpers.ThrowIfNull(type, "type");
			if (type == typeof(Grammar) || !type.IsSubclassOf(typeof(Grammar)))
			{
				throw new ArgumentException(SR.Get(SRID.StrongTypedGrammarNotAGrammar), "type");
			}
			Assembly assembly = Assembly.GetAssembly(type);
			Type[] types = assembly.GetTypes();
			foreach (Type type2 in types)
			{
				string s = null;
				if ((!(type2 == type) && !type2.IsSubclassOf(type)) || !(type2.GetField("__cultureId") != null))
				{
					continue;
				}
				try
				{
					s = (string)type2.InvokeMember("__cultureId", BindingFlags.GetField, null, null, null, null);
				}
				catch (Exception ex)
				{
					if (!(ex is MissingFieldException))
					{
						throw;
					}
				}
				if (Helpers.CompareInvariantCulture(new CultureInfo(int.Parse(s, CultureInfo.InvariantCulture)), CultureInfo.CurrentUICulture))
				{
					try
					{
						return (Grammar)assembly.CreateInstance(type2.FullName, ignoreCase: false, BindingFlags.CreateInstance, null, onInitParameters, null, null);
					}
					catch (MissingMemberException)
					{
						throw new ArgumentException(SR.Get(SRID.RuleScriptInvalidParameters, type2.Name, type2.Name));
					}
				}
			}
			return null;
		}

		internal static Grammar Create(string grammarName, string ruleName, string onInitParameter, out Uri redirectUri)
		{
			redirectUri = null;
			grammarName = grammarName.Trim();
			Uri result;
			bool flag = Uri.TryCreate(grammarName, UriKind.Absolute, out result);
			int num = grammarName.IndexOf(".dll", StringComparison.OrdinalIgnoreCase);
			if (!flag || (num > 0 && num == grammarName.Length - 4))
			{
				Assembly assembly;
				if (flag)
				{
					if (!result.IsFile)
					{
						throw new InvalidOperationException();
					}
					assembly = Assembly.LoadFrom(result.LocalPath);
				}
				else
				{
					assembly = Assembly.Load(grammarName);
				}
				return LoadGrammarFromAssembly(assembly, ruleName, onInitParameter);
			}
			try
			{
				string localPath;
				using Stream stream = _resourceLoader.LoadFile(result, out localPath, out redirectUri);
				try
				{
					return new Grammar(onInitParameter, stream, ruleName);
				}
				finally
				{
					_resourceLoader.UnloadFile(localPath);
				}
			}
			catch
			{
				Assembly assembly2 = Assembly.LoadFrom(grammarName);
				return LoadGrammarFromAssembly(assembly2, ruleName, onInitParameter);
			}
		}

		internal void OnRecognitionInternal(SpeechRecognizedEventArgs eventArgs)
		{
			this.SpeechRecognized?.Invoke(this, eventArgs);
		}

		internal static bool IsDictationGrammar(Uri uri)
		{
			if (uri == null || !uri.IsAbsoluteUri || uri.Scheme != "grammar" || !string.IsNullOrEmpty(uri.Host) || !string.IsNullOrEmpty(uri.Authority) || !string.IsNullOrEmpty(uri.Query) || uri.PathAndQuery != "dictation")
			{
				return false;
			}
			return true;
		}

		internal bool IsDictation(Uri uri)
		{
			bool flag = IsDictationGrammar(uri);
			if (!flag && this is DictationGrammar)
			{
				throw new ArgumentException(SR.Get(SRID.DictationInvalidTopic), "uri");
			}
			return flag;
		}

		internal Grammar Find(long grammarId)
		{
			if (_ruleRefs != null)
			{
				foreach (Grammar ruleRef in _ruleRefs)
				{
					if (grammarId == ruleRef._sapiGrammarId)
					{
						return ruleRef;
					}
					Grammar result;
					if ((result = ruleRef.Find(grammarId)) != null)
					{
						return result;
					}
				}
			}
			return null;
		}

		internal Grammar Find(string ruleName)
		{
			if (_ruleRefs != null)
			{
				foreach (Grammar ruleRef in _ruleRefs)
				{
					if (ruleName == ruleRef.RuleName)
					{
						return ruleRef;
					}
					Grammar result;
					if ((result = ruleRef.Find(ruleName)) != null)
					{
						return result;
					}
				}
			}
			return null;
		}

		internal void AddRuleRef(Grammar ruleRef, uint grammarId)
		{
			if (_ruleRefs == null)
			{
				_ruleRefs = new Collection<Grammar>();
			}
			_ruleRefs.Add(ruleRef);
			_sapiGrammarId = grammarId;
		}

		internal MethodInfo MethodInfo(string method)
		{
			return GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		private void LoadAndCompileCfgData(bool isImportedGrammar, bool stgInit)
		{
			Stream stream = (IsStg ? LoadCfgFromResource(stgInit) : LoadCfg(isImportedGrammar, stgInit));
			SrgsRule[] array = RunOnInit(IsStg);
			if (array != null)
			{
				MemoryStream memoryStream = CombineCfg(_ruleName, stream, array);
				stream.Close();
				stream = memoryStream;
			}
			_cfgData = Helpers.ReadStreamToByteArray(stream, (int)stream.Length);
			stream.Close();
			_srgsDocument = null;
			_appStream = null;
		}

		private MemoryStream LoadCfg(bool isImportedGrammar, bool stgInit)
		{
			Uri uri = Uri;
			MemoryStream memoryStream = new MemoryStream();
			if (uri != null)
			{
				string mimeType;
				string localPath;
				using (Stream stream = _resourceLoader.LoadFile(uri, out mimeType, out _baseUri, out localPath))
				{
					stream.Position = 0L;
					SrgsGrammarCompiler.CompileXmlOrCopyCfg(stream, memoryStream, uri);
				}
				_resourceLoader.UnloadFile(localPath);
			}
			else if (_srgsDocument != null)
			{
				SrgsGrammarCompiler.Compile(_srgsDocument, memoryStream);
				if (_baseUri == null && _srgsDocument.BaseUri != null)
				{
					_baseUri = _srgsDocument.BaseUri;
				}
			}
			else if (_grammarBuilder != null)
			{
				_grammarBuilder.Compile(memoryStream);
			}
			else
			{
				SrgsGrammarCompiler.CompileXmlOrCopyCfg(_appStream, memoryStream, null);
			}
			memoryStream.Position = 0L;
			_ruleName = CheckRuleName(memoryStream, _ruleName, isImportedGrammar, stgInit, out _sapi53Only, out _semanticTag);
			CreateSandbox(memoryStream);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		private static Grammar LoadGrammarFromAssembly(Assembly assembly, string ruleName, string onInitParameters)
		{
			Type typeFromHandle = typeof(Grammar);
			Type type = null;
			Type[] types = assembly.GetTypes();
			foreach (Type type2 in types)
			{
				if (!type2.IsSubclassOf(typeFromHandle))
				{
					continue;
				}
				string s = null;
				if (type2.Name == ruleName)
				{
					type = type2;
				}
				if ((!(type2 == type) && (!(type != null) || !type2.IsSubclassOf(type))) || !(type2.GetField("__cultureId") != null))
				{
					continue;
				}
				try
				{
					s = (string)type2.InvokeMember("__cultureId", BindingFlags.GetField, null, null, null, null);
				}
				catch (Exception ex)
				{
					if (!(ex is MissingFieldException))
					{
						throw;
					}
				}
				if (Helpers.CompareInvariantCulture(new CultureInfo(int.Parse(s, CultureInfo.InvariantCulture)), CultureInfo.CurrentUICulture))
				{
					try
					{
						object[] args = MatchInitParameters(type2, onInitParameters, assembly.GetName().Name, ruleName);
						return (Grammar)assembly.CreateInstance(type2.FullName, ignoreCase: false, BindingFlags.CreateInstance, null, args, null, null);
					}
					catch (MissingMemberException)
					{
						throw new ArgumentException(SR.Get(SRID.RuleScriptInvalidParameters, type2.Name, type2.Name));
					}
				}
			}
			return null;
		}

		private static object[] MatchInitParameters(Type type, string onInitParameters, string grammar, string rule)
		{
			ConstructorInfo[] constructors = type.GetConstructors();
			NameValuePair[] array = ParseInitParams(onInitParameters);
			object[] array2 = new object[array.Length];
			bool flag = false;
			for (int i = 0; i < constructors.Length; i++)
			{
				if (flag)
				{
					break;
				}
				ParameterInfo[] parameters = constructors[i].GetParameters();
				if (parameters.Length > array.Length)
				{
					continue;
				}
				flag = true;
				for (int j = 0; j < array.Length &