Decompiled source of DEPO VoiceChat v1.0.4

DEPOVoiceChat.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using CSCore;
using CSCore.CoreAudioAPI;
using CSCore.SoundIn;
using CSCore.SoundOut;
using CSCore.Streams;
using Steamworks;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DEPOVoiceChat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DEPOVoiceChat")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("04bd0ec2-8038-494e-a523-c810f2f5b373")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DEPOVoiceChat;

public static class Localization
{
	public enum Language
	{
		English,
		Russian,
		Spanish,
		French,
		Chinese,
		Japanese
	}

	private static readonly Dictionary<string, Dictionary<Language, string>> texts = new Dictionary<string, Dictionary<Language, string>>
	{
		{
			"connected_clients",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Connected clients:"
				},
				{
					Language.Russian,
					"Подключено клиентов:"
				},
				{
					Language.Spanish,
					"Clientes conectados:"
				},
				{
					Language.Chinese,
					"已连接的客户端:"
				},
				{
					Language.Japanese,
					"接続中のクライアント:"
				},
				{
					Language.French,
					"Clients connectés :"
				}
			}
		},
		{
			"volume_players",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Volume players"
				},
				{
					Language.Russian,
					"Громкость игроков"
				},
				{
					Language.Spanish,
					"Volumen de jugadores"
				},
				{
					Language.Chinese,
					"玩家音量"
				},
				{
					Language.Japanese,
					"プレイヤーの音量"
				},
				{
					Language.French,
					"Volume des joueurs"
				}
			}
		},
		{
			"volume_microphone",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Volume microphone"
				},
				{
					Language.Russian,
					"Громкость микрофона"
				},
				{
					Language.Spanish,
					"Volumen del micrófono"
				},
				{
					Language.Chinese,
					"麦克风音量"
				},
				{
					Language.Japanese,
					"マイクの音量"
				},
				{
					Language.French,
					"Volume du micro"
				}
			}
		},
		{
			"hear_myself",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Hear myself"
				},
				{
					Language.Russian,
					"Слушать себя"
				},
				{
					Language.Spanish,
					"Escucharme a mí mismo"
				},
				{
					Language.Chinese,
					"听自己的声音"
				},
				{
					Language.Japanese,
					"自分の声を聞く"
				},
				{
					Language.French,
					"S'entendre soi-même"
				}
			}
		},
		{
			"select_microphone",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Select microphone"
				},
				{
					Language.Russian,
					"Выбрать микрофон"
				},
				{
					Language.Spanish,
					"Seleccionar micrófono"
				},
				{
					Language.Chinese,
					"选择麦克风"
				},
				{
					Language.Japanese,
					"マイクを選択"
				},
				{
					Language.French,
					"Sélectionner le micro"
				}
			}
		},
		{
			"keybinds",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Keybinds:"
				},
				{
					Language.Russian,
					"Назначение клавиш:"
				},
				{
					Language.Spanish,
					"Asignación de teclas:"
				},
				{
					Language.Chinese,
					"按键绑定:"
				},
				{
					Language.Japanese,
					"キー割り当て:"
				},
				{
					Language.French,
					"Raccourcis clavier :"
				}
			}
		},
		{
			"open_close_menu",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Open/Close menu"
				},
				{
					Language.Russian,
					"Открыть/Закрыть меню"
				},
				{
					Language.Spanish,
					"Abrir/Cerrar menú"
				},
				{
					Language.Chinese,
					"打开/关闭菜单"
				},
				{
					Language.Japanese,
					"メニューを開閉"
				},
				{
					Language.French,
					"Ouvrir/Fermer le menu"
				}
			}
		},
		{
			"push_to_talk",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Push-to-talk"
				},
				{
					Language.Russian,
					"Нажать, чтобы разговаривать"
				},
				{
					Language.Spanish,
					"Pulsar para hablar"
				},
				{
					Language.Chinese,
					"按键发言"
				},
				{
					Language.Japanese,
					"プッシュ・トゥ・トーク"
				},
				{
					Language.French,
					"Appuyer pour parler"
				}
			}
		},
		{
			"close",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Close"
				},
				{
					Language.Russian,
					"Закрыть"
				},
				{
					Language.Spanish,
					"Cerrar"
				},
				{
					Language.Chinese,
					"关闭"
				},
				{
					Language.Japanese,
					"閉じる"
				},
				{
					Language.French,
					"Fermer"
				}
			}
		},
		{
			"microphone_mode",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Microphone mode:"
				},
				{
					Language.Russian,
					"Режим микрофона:"
				},
				{
					Language.Spanish,
					"Modo micrófono:"
				},
				{
					Language.Chinese,
					"麦克风模式:"
				},
				{
					Language.Japanese,
					"マイクモード:"
				},
				{
					Language.French,
					"Mode micro :"
				}
			}
		},
		{
			"threshold",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Voice threshold"
				},
				{
					Language.Russian,
					"Порог громкости"
				},
				{
					Language.Spanish,
					"Umbral de voz"
				},
				{
					Language.Chinese,
					"语音激活阈值"
				},
				{
					Language.Japanese,
					"音声認識しきい値"
				},
				{
					Language.French,
					"Seuil de voix"
				}
			}
		},
		{
			"voicechat_menu",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Voicechat Menu"
				},
				{
					Language.Russian,
					"Меню голосового чата"
				},
				{
					Language.Spanish,
					"Menú de Voicechat"
				},
				{
					Language.Chinese,
					"语音聊天菜单"
				},
				{
					Language.Japanese,
					"ボイスチャットメニュー"
				},
				{
					Language.French,
					"Menu de chat vocal"
				}
			}
		},
		{
			"voice_activation",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Voice Activation"
				},
				{
					Language.Russian,
					"Активация голосом"
				},
				{
					Language.Spanish,
					"Activación por voz"
				},
				{
					Language.Chinese,
					"语音激活"
				},
				{
					Language.Japanese,
					"音声アクティベーション"
				},
				{
					Language.French,
					"Activation vocale"
				}
			}
		},
		{
			"buffer_size",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Buffer size (ms)"
				},
				{
					Language.Russian,
					"Размер буфера (мс)"
				},
				{
					Language.Spanish,
					"Tamaño del búfer (ms)"
				},
				{
					Language.Chinese,
					"缓冲区大小(毫秒)"
				},
				{
					Language.Japanese,
					"バッファサイズ(ms)"
				},
				{
					Language.French,
					"Taille du tampon (ms)"
				}
			}
		},
		{
			"buffer_current",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Current buffer:"
				},
				{
					Language.Russian,
					"Текущий буфер:"
				},
				{
					Language.Spanish,
					"Búfer actual:"
				},
				{
					Language.Chinese,
					"当前缓冲:"
				},
				{
					Language.Japanese,
					"現在のバッファ:"
				},
				{
					Language.French,
					"Tampon actuel :"
				}
			}
		},
		{
			"language",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Language"
				},
				{
					Language.Russian,
					"Язык"
				},
				{
					Language.Spanish,
					"Idioma"
				},
				{
					Language.Chinese,
					"语言"
				},
				{
					Language.Japanese,
					"言語"
				},
				{
					Language.French,
					"Langue"
				}
			}
		},
		{
			"speaking",
			new Dictionary<Language, string>
			{
				{
					Language.English,
					"Speaking..."
				},
				{
					Language.Russian,
					"Говорит..."
				},
				{
					Language.Spanish,
					"Hablando..."
				},
				{
					Language.Chinese,
					"正在讲话..."
				},
				{
					Language.Japanese,
					"話しています..."
				},
				{
					Language.French,
					"Parle..."
				}
			}
		}
	};

	public static Language CurrentLanguage { get; private set; } = Language.English;


	public static string T(string key)
	{
		if (texts.TryGetValue(key, out var value) && value.TryGetValue(CurrentLanguage, out var value2))
		{
			return value2;
		}
		return key;
	}

	public static void SetLanguage(string lang)
	{
		switch (lang)
		{
		case "English":
			CurrentLanguage = Language.English;
			break;
		case "Russian (Русский)":
			CurrentLanguage = Language.Russian;
			break;
		case "Spanish (Español)":
			CurrentLanguage = Language.Spanish;
			break;
		case "French (Français)":
			CurrentLanguage = Language.French;
			break;
		case "Chinese (中文)":
			CurrentLanguage = Language.Chinese;
			break;
		case "Japanese (日本語)":
			CurrentLanguage = Language.Japanese;
			break;
		default:
			CurrentLanguage = Language.English;
			break;
		}
	}
}
[BepInPlugin("ru.makorddev.depovoicechat", "Voicechat", "1.0.0")]
public class Main : BaseUnityPlugin
{
	public static IPEndPoint ServerEP;

	private readonly CancellationTokenSource cts = new CancellationTokenSource();

	private UI ui;

	private async void Awake()
	{
		Debug.Log((object)"[VoiceChat] VoiceChat loaded.");
		try
		{
			IPAddress[] addr = null;
			int retries = 3;
			while (retries-- > 0)
			{
				try
				{
					addr = await Dns.GetHostAddressesAsync("busiatep.ru");
					if (addr.Length != 0)
					{
						break;
					}
				}
				catch
				{
					await Task.Delay(1000);
				}
			}
			if (addr == null || addr.Length == 0)
			{
				Debug.LogError((object)"[VoiceChat] DNS failed after retries.");
				ServerEP = new IPEndPoint(IPAddress.Loopback, 6001);
			}
			else
			{
				ServerEP = new IPEndPoint(addr[0], 6001);
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] DNS exception: " + ex));
			ServerEP = new IPEndPoint(IPAddress.Loopback, 6001);
		}
		try
		{
			SettingsManager.Load();
		}
		catch
		{
			Debug.LogError((object)"[VoiceChat] Failed to load settings.");
		}
		try
		{
			VoiceManager.InitDevices();
		}
		catch
		{
			Debug.LogError((object)"[VoiceChat] Failed to init devices.");
		}
		InitializeSteam();
		SceneManager.activeSceneChanged += OnSceneChanged;
		try
		{
			Localization.SetLanguage(SettingsManager.CurrentSettings.language);
		}
		catch
		{
			Debug.LogWarning((object)"[VoiceChat] Failed to set language.");
		}
		GameObject uiObj = new GameObject("VoiceChatUI");
		ui = uiObj.AddComponent<UI>();
		Object.DontDestroyOnLoad((Object)(object)uiObj);
	}

	private async void Start()
	{
		VoiceManager.SetInstanceId(Guid.NewGuid().ToString());
		bool connected = false;
		int attempts = 3;
		while (!connected && attempts-- > 0)
		{
			try
			{
				connected = await NetworkManager.Connect();
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[VoiceChat] Connect attempt failed: " + ex));
			}
			if (!connected)
			{
				await Task.Delay(2000);
			}
		}
		if (!connected)
		{
			Debug.LogError((object)"[VoiceChat] Failed to connect to server after retries.");
			return;
		}
		NetworkManager.OnReconnected += delegate
		{
			try
			{
				VoiceManager.RestartUdp();
			}
			catch (Exception ex4)
			{
				Debug.LogWarning((object)("[VoiceChat] Failed to restart UDP: " + ex4));
			}
		};
		try
		{
			if (VoiceManager.MicDevices.Length != 0)
			{
				int idx = Mathf.Clamp(SettingsManager.CurrentSettings.selectedMicIndex, 0, VoiceManager.MicDevices.Length - 1);
				VoiceManager.StartCapture(idx);
			}
		}
		catch (Exception ex2)
		{
			Debug.LogError((object)("[VoiceChat] Failed to start mic capture: " + ex2));
		}
		try
		{
			await VoiceManager.StartReceiving(cts.Token);
		}
		catch (Exception ex3)
		{
			Debug.LogError((object)("[VoiceChat] Failed to start receiving voice: " + ex3));
		}
	}

	private void OnDestroy()
	{
		try
		{
			cts?.Cancel();
		}
		catch
		{
		}
		try
		{
			NetworkManager.Disconnect();
		}
		catch
		{
		}
		try
		{
			VoiceManager.StopCapture();
		}
		catch
		{
		}
		try
		{
			VoiceManager.StopReceiving();
		}
		catch
		{
		}
		try
		{
			VoiceManager.StopVoiceStream();
		}
		catch
		{
		}
		GameObject val = GameObject.Find("Dispatcher");
		if ((Object)(object)val != (Object)null)
		{
			try
			{
				Object.Destroy((Object)(object)val);
			}
			catch
			{
			}
		}
	}

	private void Update()
	{
		try
		{
			SpeakingIndicator.UpdateSpeakingIndicators();
			ui?.UpdateUI();
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] Update error: " + ex));
		}
	}

	private void OnGUI()
	{
		ui?.DrawUI();
	}

	private void OnSceneChanged(Scene oldScene, Scene newScene)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		Task.Run(async delegate
		{
			try
			{
				string msg = $"INFO|{SteamUser.GetSteamID().m_SteamID}|{SteamFriends.GetPersonaName()}|{((Scene)(ref newScene)).name}";
				await NetworkManager.SendMessage(msg);
			}
			catch
			{
				Debug.LogWarning((object)"[VoiceChat] Failed to send scene info.");
			}
		});
		if ((Object)(object)GameObject.Find("Dispatcher") == (Object)null)
		{
			GameObject val = new GameObject("Dispatcher");
			try
			{
				val.AddComponent<UnityMainThreadDispatcher>();
			}
			catch
			{
			}
			Object.DontDestroyOnLoad((Object)(object)val);
		}
	}

	private void InitializeSteam()
	{
		try
		{
			if (!SteamAPI.Init())
			{
				Debug.LogError((object)"[VoiceChat] SteamAPI init failed!");
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] SteamAPI exception: " + ex));
		}
	}
}
public static class NetworkManager
{
	public enum ConnectionState
	{
		Disconnected,
		Connecting,
		Connected
	}

	private static TcpClient tcpClient;

	private static NetworkStream stream;

	private static CancellationTokenSource cts;

	private static CancellationTokenSource monitorCts;

	private static readonly string serverIp = "busiatep.ru";

	private static readonly int serverPort = 6000;

	private static readonly int heartbeatInterval = 5000;

	private static string lastMessage = "";

	private static readonly object msgLock = new object();

	private static bool reconnecting = false;

	public static ConnectionState State { get; private set; } = ConnectionState.Disconnected;


	public static Dictionary<string, string> ClientList { get; private set; } = new Dictionary<string, string>();


	public static TcpClient Client => tcpClient;

	public static NetworkStream Stream => stream;

	public static event Action OnReconnected;

	public static async Task<bool> Connect()
	{
		if (State == ConnectionState.Connecting || State == ConnectionState.Connected)
		{
			return State == ConnectionState.Connected;
		}
		State = ConnectionState.Connecting;
		Cleanup();
		cts = new CancellationTokenSource();
		CancellationToken token = cts.Token;
		try
		{
			tcpClient = new TcpClient();
			await tcpClient.ConnectAsync(serverIp, serverPort);
			stream = tcpClient.GetStream();
			Debug.Log((object)"[VoiceChat] TCP connected.");
			object arg = SteamUser.GetSteamID().m_SteamID;
			string personaName = SteamFriends.GetPersonaName();
			Scene activeScene = SceneManager.GetActiveScene();
			string info = $"INFO|{arg}|{personaName}|{((Scene)(ref activeScene)).name}";
			await SendMessage(info);
			if (!(await WaitForResponse("CLIENTS|", 2000)))
			{
				Debug.LogWarning((object)"[VoiceChat] CLIENTS response timeout.");
			}
			Task.Run(() => HeartbeatLoop(token), token);
			Task.Run(() => ReceiveLoop(token), token);
			State = ConnectionState.Connected;
			StartMonitor();
			return true;
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] Connect error: " + ex));
			Disconnect();
			StartReconnectLoop();
			return false;
		}
	}

	private static void StartMonitor()
	{
		monitorCts?.Cancel();
		monitorCts = new CancellationTokenSource();
		CancellationToken token = monitorCts.Token;
		Task.Run(async delegate
		{
			while (!token.IsCancellationRequested)
			{
				try
				{
					await Task.Delay(3000, token);
					if (State != ConnectionState.Connected && !reconnecting)
					{
						Debug.LogWarning((object)"[VoiceChat] Connection lost. Trying to reconnect...");
						StartReconnectLoop();
					}
				}
				catch (TaskCanceledException)
				{
					break;
				}
				catch (Exception ex2)
				{
					Debug.LogError((object)("[VoiceChat] Monitor error: " + ex2));
				}
			}
		}, token);
	}

	private static void StartReconnectLoop()
	{
		if (reconnecting)
		{
			return;
		}
		reconnecting = true;
		Task.Run(async delegate
		{
			int delay = 3000;
			while (State != ConnectionState.Connected)
			{
				Debug.Log((object)$"[VoiceChat] Reconnecting in {delay / 1000}s...");
				await Task.Delay(delay);
				if (await Connect())
				{
					reconnecting = false;
					NetworkManager.OnReconnected?.Invoke();
					return;
				}
				delay = Math.Min(delay + 3000, 10000);
			}
			reconnecting = false;
		});
	}

	public static async Task SendMessage(string msg)
	{
		if (tcpClient != null && tcpClient.Connected)
		{
			byte[] data = Encoding.UTF8.GetBytes(msg);
			try
			{
				await stream.WriteAsync(data, 0, data.Length);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[VoiceChat] Failed to send TCP message: " + ex));
				Disconnect();
				StartReconnectLoop();
			}
		}
		else if (!reconnecting)
		{
			StartReconnectLoop();
		}
	}

	private static async Task HeartbeatLoop(CancellationToken token)
	{
		try
		{
			while (!token.IsCancellationRequested)
			{
				await Task.Delay(heartbeatInterval, token).ContinueWith(delegate
				{
				});
				if (token.IsCancellationRequested)
				{
					break;
				}
				await SendMessage("HEARTBEAT");
			}
		}
		catch (TaskCanceledException)
		{
		}
		catch (Exception ex2)
		{
			Debug.LogError((object)("[VoiceChat] HeartbeatLoop error: " + ex2));
		}
	}

	private static async Task ReceiveLoop(CancellationToken token)
	{
		byte[] buffer = new byte[4096];
		try
		{
			while (!token.IsCancellationRequested)
			{
				int read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
				if (read == 0)
				{
					break;
				}
				string message = Encoding.UTF8.GetString(buffer, 0, read);
				HandleServerMessage(message);
			}
		}
		catch (TaskCanceledException)
		{
		}
		catch (Exception ex2)
		{
			Debug.LogWarning((object)("[VoiceChat] ReceiveLoop error: " + ex2));
		}
		finally
		{
			Debug.LogWarning((object)"[VoiceChat] TCP connection lost. Disconnecting...");
			Disconnect();
			StartReconnectLoop();
		}
	}

	private static void HandleServerMessage(string message)
	{
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		lock (msgLock)
		{
			lastMessage = message;
		}
		try
		{
			if (message.StartsWith("CLIENTS"))
			{
				ClientList.Clear();
				string[] array = message.Split(new char[1] { '|' });
				if (array.Length <= 1)
				{
					return;
				}
				string[] array2 = array[1].Split(new char[1] { ',' });
				foreach (string text in array2)
				{
					string[] array3 = text.Split(new char[1] { ':' });
					if (array3.Length == 2)
					{
						ClientList[array3[0]] = array3[1];
					}
				}
			}
			else
			{
				if (!message.StartsWith("SPEAKING|"))
				{
					return;
				}
				string[] array4 = message.Split(new char[1] { '|' });
				if (array4.Length == 4)
				{
					string text2 = array4[1];
					string name = array4[2];
					Scene activeScene = SceneManager.GetActiveScene();
					if (((Scene)(ref activeScene)).name == text2)
					{
						VoiceManager.AllowScenePlayback(text2, name);
					}
				}
			}
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[VoiceChat] HandleServerMessage error: " + ex));
		}
	}

	public static async Task<bool> WaitForResponse(string expected, int timeoutMs)
	{
		int waited = 0;
		while (waited < timeoutMs)
		{
			string msg;
			lock (msgLock)
			{
				msg = lastMessage;
			}
			if (msg.Contains(expected))
			{
				return true;
			}
			await Task.Delay(10);
			waited += 10;
			msg = null;
		}
		return false;
	}

	public static void Disconnect()
	{
		try
		{
			State = ConnectionState.Disconnected;
			cts?.Cancel();
			monitorCts?.Cancel();
			stream?.Close();
			tcpClient?.Close();
			tcpClient = null;
			stream = null;
			cts = null;
			monitorCts = null;
		}
		catch
		{
		}
	}

	private static void Cleanup()
	{
		try
		{
			cts?.Cancel();
			monitorCts?.Cancel();
			stream?.Close();
			tcpClient?.Close();
			tcpClient = null;
			stream = null;
			cts = null;
			monitorCts = null;
		}
		catch
		{
		}
	}
}
public enum MicMode
{
	PushToTalk,
	VoiceActivation
}
[Serializable]
public class VoiceSettings
{
	public float selfVolume = 1f;

	public float playersVolume = 1f;

	public bool hearSelf = false;

	public int selectedMicIndex = 0;

	public KeyCode menuToggleKey = (KeyCode)113;

	public KeyCode pushToTalkKey = (KeyCode)114;

	public MicMode micMode = MicMode.PushToTalk;

	public float voiceThresholdDb = -5f;

	public string language = "English";

	public int bufferSizeMs = 20;
}
public static class SettingsManager
{
	private static readonly string settingsPath = Path.Combine(Application.persistentDataPath, "voicechat_settings.json");

	public static VoiceSettings CurrentSettings { get; private set; } = new VoiceSettings();


	public static void Load()
	{
		if (File.Exists(settingsPath))
		{
			try
			{
				string text = File.ReadAllText(settingsPath);
				CurrentSettings = JsonUtility.FromJson<VoiceSettings>(text);
			}
			catch
			{
				CurrentSettings = new VoiceSettings();
			}
		}
		Localization.SetLanguage(CurrentSettings.language);
	}

	public static void Save()
	{
		try
		{
			string contents = JsonUtility.ToJson((object)CurrentSettings, true);
			File.WriteAllText(settingsPath, contents);
		}
		catch
		{
		}
	}
}
public class SpeakingIndicator : MonoBehaviour
{
	public static readonly Dictionary<string, float> speakingPlayers = new Dictionary<string, float>();

	public static readonly Dictionary<string, Coroutine> activeCoroutines = new Dictionary<string, Coroutine>();

	public static readonly object lockObj = new object();

	public static string speakText = "[" + Localization.T("speaking") + "]";

	private static string oldSpeakText;

	private const float silenceTimeout = 1f;

	public static void UpdateSpeakingIndicators()
	{
		float time = Time.time;
		List<string> list = new List<string>();
		if (speakText != "[" + Localization.T("speaking") + "]")
		{
			UpdateSpeakText();
		}
		lock (lockObj)
		{
			foreach (KeyValuePair<string, float> speakingPlayer in speakingPlayers)
			{
				if (time - speakingPlayer.Value > 1f)
				{
					list.Add(speakingPlayer.Key);
				}
			}
			foreach (string item in list)
			{
				speakingPlayers.Remove(item);
			}
		}
		foreach (string item2 in list)
		{
			RemoveIndicator(item2);
		}
	}

	public static void UpdateSpeakText()
	{
		oldSpeakText = speakText;
		speakText = "[" + Localization.T("speaking") + "]";
		UnityMainThreadDispatcher.Enqueue(delegate
		{
			Text[] array = Object.FindObjectsOfType<Text>(true);
			Text[] array2 = array;
			foreach (Text val in array2)
			{
				if (!string.IsNullOrEmpty(oldSpeakText) && val.text.Contains(oldSpeakText))
				{
					val.text = val.text.Replace(oldSpeakText, speakText);
				}
			}
		});
	}

	public static void OnPlayerSpeaking(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			Debug.LogWarning((object)"[SpeakingIndicator] OnPlayerSpeaking called with null or empty name");
			return;
		}
		bool flag = false;
		lock (lockObj)
		{
			speakingPlayers[name] = Time.time;
			if (!activeCoroutines.ContainsKey(name))
			{
				flag = true;
			}
		}
		if (!flag)
		{
			return;
		}
		UnityMainThreadDispatcher.Enqueue(delegate
		{
			Coroutine value = StartAddIndicatorCoroutine(name);
			lock (lockObj)
			{
				activeCoroutines[name] = value;
			}
		});
	}

	private static Coroutine StartAddIndicatorCoroutine(string playerName)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Expected O, but got Unknown
		GameObject val = new GameObject("DispatcherCoroutine_" + playerName);
		DispatcherCoroutineRunner dispatcherCoroutineRunner = val.AddComponent<DispatcherCoroutineRunner>();
		return ((MonoBehaviour)dispatcherCoroutineRunner).StartCoroutine(dispatcherCoroutineRunner.AddIndicatorCoroutine(playerName));
	}

	private static void RemoveIndicator(string playerName)
	{
		UnityMainThreadDispatcher.Enqueue(delegate
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			GameObject val = new GameObject("DispatcherRemove_" + playerName);
			DispatcherCoroutineRunner dispatcherCoroutineRunner = val.AddComponent<DispatcherCoroutineRunner>();
			((MonoBehaviour)dispatcherCoroutineRunner).StartCoroutine(dispatcherCoroutineRunner.RemoveIndicatorCoroutine(playerName));
		});
	}

	public static Text FindTextForPlayer(string playerName)
	{
		Text[] source = Object.FindObjectsOfType<Text>(true);
		Text val = ((IEnumerable<Text>)source).FirstOrDefault((Func<Text, bool>)((Text t) => ((Object)t).name.Contains("NameJugador") && t.text.Contains(playerName)));
		if ((Object)(object)val == (Object)null)
		{
			Debug.LogWarning((object)("[SpeakingIndicator] FindTextForPlayer: Could not find Text for '" + playerName + "'"));
		}
		return val;
	}
}
public class DispatcherCoroutineRunner : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <AddIndicatorCoroutine>d__0 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string playerName;

		public DispatcherCoroutineRunner <>4__this;

		private Text <playerText>5__1;

		private Outline <outline>5__2;

		private bool <stillSpeaking>5__3;

		private object <>s__4;

		private bool <>s__5;

		private object <>s__6;

		private bool <>s__7;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <AddIndicatorCoroutine>d__0(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<playerText>5__1 = null;
			<outline>5__2 = null;
			<>s__4 = null;
			<>s__6 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<playerText>5__1 = SpeakingIndicator.FindTextForPlayer(playerName);
				if ((Object)(object)<playerText>5__1 == (Object)null)
				{
					return false;
				}
				if (!<playerText>5__1.text.Contains(SpeakingIndicator.speakText))
				{
					Text obj = <playerText>5__1;
					obj.text = obj.text + " " + SpeakingIndicator.speakText;
				}
				<outline>5__2 = ((Component)<playerText>5__1).GetComponent<Outline>();
				if ((Object)(object)<outline>5__2 != (Object)null)
				{
					((Behaviour)<outline>5__2).enabled = false;
					<>2__current = (object)new WaitForSeconds(0.01f);
					<>1__state = 1;
					return true;
				}
				goto IL_0180;
			case 1:
				<>1__state = -1;
				((Behaviour)<outline>5__2).enabled = true;
				goto IL_0180;
			case 2:
				<>1__state = -1;
				goto IL_0180;
			case 3:
				{
					<>1__state = -1;
					((Behaviour)<outline>5__2).enabled = true;
					break;
				}
				IL_0180:
				<>s__4 = SpeakingIndicator.lockObj;
				<>s__5 = false;
				try
				{
					Monitor.Enter(<>s__4, ref <>s__5);
					<stillSpeaking>5__3 = SpeakingIndicator.speakingPlayers.ContainsKey(playerName);
				}
				finally
				{
					if (<>s__5)
					{
						Monitor.Exit(<>s__4);
					}
				}
				<>s__4 = null;
				if (<stillSpeaking>5__3)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				if ((Object)(object)<playerText>5__1 != (Object)null && <playerText>5__1.text.Contains(SpeakingIndicator.speakText))
				{
					<playerText>5__1.text = <playerText>5__1.text.Replace(" " + SpeakingIndicator.speakText, "");
				}
				if ((Object)(object)<outline>5__2 != (Object)null)
				{
					((Behaviour)<outline>5__2).enabled = false;
					<>2__current = (object)new WaitForSeconds(0.01f);
					<>1__state = 3;
					return true;
				}
				break;
			}
			<>s__6 = SpeakingIndicator.lockObj;
			<>s__7 = false;
			try
			{
				Monitor.Enter(<>s__6, ref <>s__7);
				SpeakingIndicator.activeCoroutines.Remove(playerName);
			}
			finally
			{
				if (<>s__7)
				{
					Monitor.Exit(<>s__6);
				}
			}
			<>s__6 = null;
			VoiceManager.RemoveFromSpeaking(playerName);
			Object.Destroy((Object)(object)((Component)<>4__this).gameObject);
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <RemoveIndicatorCoroutine>d__1 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string playerName;

		public DispatcherCoroutineRunner <>4__this;

		private Text <playerText>5__1;

		private Outline <outline>5__2;

		private object <>s__3;

		private bool <>s__4;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <RemoveIndicatorCoroutine>d__1(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<playerText>5__1 = null;
			<outline>5__2 = null;
			<>s__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
			{
				<>1__state = -1;
				<playerText>5__1 = SpeakingIndicator.FindTextForPlayer(playerName);
				if ((Object)(object)<playerText>5__1 != (Object)null && <playerText>5__1.text.Contains(SpeakingIndicator.speakText))
				{
					<playerText>5__1.text = <playerText>5__1.text.Replace(" " + SpeakingIndicator.speakText, "");
				}
				Text obj = <playerText>5__1;
				<outline>5__2 = ((obj != null) ? ((Component)obj).GetComponent<Outline>() : null);
				if ((Object)(object)<outline>5__2 != (Object)null)
				{
					((Behaviour)<outline>5__2).enabled = false;
					<>2__current = (object)new WaitForSeconds(0.01f);
					<>1__state = 1;
					return true;
				}
				break;
			}
			case 1:
				<>1__state = -1;
				((Behaviour)<outline>5__2).enabled = true;
				break;
			}
			<>s__3 = SpeakingIndicator.lockObj;
			<>s__4 = false;
			try
			{
				Monitor.Enter(<>s__3, ref <>s__4);
				SpeakingIndicator.activeCoroutines.Remove(playerName);
			}
			finally
			{
				if (<>s__4)
				{
					Monitor.Exit(<>s__3);
				}
			}
			<>s__3 = null;
			VoiceManager.RemoveFromSpeaking(playerName);
			Object.Destroy((Object)(object)((Component)<>4__this).gameObject);
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[IteratorStateMachine(typeof(<AddIndicatorCoroutine>d__0))]
	public IEnumerator AddIndicatorCoroutine(string playerName)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <AddIndicatorCoroutine>d__0(0)
		{
			<>4__this = this,
			playerName = playerName
		};
	}

	[IteratorStateMachine(typeof(<RemoveIndicatorCoroutine>d__1))]
	public IEnumerator RemoveIndicatorCoroutine(string playerName)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <RemoveIndicatorCoroutine>d__1(0)
		{
			<>4__this = this,
			playerName = playerName
		};
	}
}
public class UI : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <WaitForKeyPressed>d__17 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public Action<KeyCode> callback;

		public UI <>4__this;

		private IEnumerator <>s__1;

		private KeyCode <kcode>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <WaitForKeyPressed>d__17(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>s__1 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>4__this.waitingKey = true;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			if (<>4__this.waitingKey)
			{
				<>s__1 = Enum.GetValues(typeof(KeyCode)).GetEnumerator();
				try
				{
					while (<>s__1.MoveNext())
					{
						<kcode>5__2 = (KeyCode)<>s__1.Current;
						if (Input.GetKeyDown(<kcode>5__2))
						{
							callback(<kcode>5__2);
							SettingsManager.Save();
							<>4__this.waitingKey = false;
							break;
						}
					}
				}
				finally
				{
					if (<>s__1 is IDisposable disposable)
					{
						disposable.Dispose();
					}
				}
				<>s__1 = null;
				<>2__current = null;
				<>1__state = 1;
				return true;
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private bool waitingKey = false;

	private readonly CancellationTokenSource cts = new CancellationTokenSource();

	public bool ShowMenu { get; set; } = false;


	public Rect MenuRect { get; set; } = new Rect((float)(Screen.width - 500), 100f, 400f, 600f);


	public bool MicDropdownOpen { get; set; } = false;


	public void UpdateUI()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		if (!(((Scene)(ref activeScene)).name != "menus"))
		{
			return;
		}
		if (Input.GetKeyDown(SettingsManager.CurrentSettings.menuToggleKey))
		{
			ShowMenu = !ShowMenu;
			if (!ShowMenu)
			{
				MicDropdownOpen = false;
			}
		}
		if (SettingsManager.CurrentSettings.micMode == MicMode.PushToTalk)
		{
			if (Input.GetKeyDown(SettingsManager.CurrentSettings.pushToTalkKey))
			{
				VoiceManager.StartVoiceStream(cts.Token);
			}
			if (Input.GetKeyUp(SettingsManager.CurrentSettings.pushToTalkKey))
			{
				VoiceManager.StopVoiceStream();
			}
		}
	}

	public void DrawUI()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected O, but got Unknown
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Invalid comparison between Unknown and I4
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Invalid comparison between Unknown and I4
		if (ShowMenu)
		{
			GUI.color = Color.white;
			GUI.enabled = true;
			MenuRect = GUI.Window(0, MenuRect, new WindowFunction(DrawClientMenu), Localization.T("voicechat_menu"));
			Rect menuRect = MenuRect;
			if (((Rect)(ref menuRect)).Contains(Event.current.mousePosition) && ((int)Event.current.type == 0 || (int)Event.current.type == 1 || (int)Event.current.type == 3))
			{
				Event.current.Use();
			}
			if (MicDropdownOpen)
			{
				DrawMicDropdown();
			}
		}
	}

	private void DrawMicDropdown()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		float num = 260f;
		float num2 = 24f;
		float num3 = Mathf.Min(num2 * (float)VoiceManager.MicDevices.Length, 6f * num2);
		Rect menuRect = MenuRect;
		float num4 = ((Rect)(ref menuRect)).x - num;
		menuRect = MenuRect;
		float num5 = ((Rect)(ref menuRect)).y + 190f;
		GUI.Box(new Rect(num4, num5, num, num3), "");
		Rect val = default(Rect);
		for (int i = 0; i < VoiceManager.MicDevices.Length; i++)
		{
			((Rect)(ref val))..ctor(num4, num5 + (float)i * num2, num, num2);
			if (GUI.Button(val, VoiceManager.MicDevices[i]))
			{
				SettingsManager.CurrentSettings.selectedMicIndex = i;
				SettingsManager.Save();
				VoiceManager.StopCapture();
				if (SettingsManager.CurrentSettings.hearSelf)
				{
					VoiceManager.StartCapture(i);
				}
				MicDropdownOpen = false;
			}
		}
	}

	[IteratorStateMachine(typeof(<WaitForKeyPressed>d__17))]
	public IEnumerator WaitForKeyPressed(Action<KeyCode> callback)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WaitForKeyPressed>d__17(0)
		{
			<>4__this = this,
			callback = callback
		};
	}

	private void DrawClientMenu(int windowID)
	{
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0246: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		GUILayout.Label(string.Format("{0} {1}", Localization.T("connected_clients"), NetworkManager.ClientList.Count), Array.Empty<GUILayoutOption>());
		GUILayout.Label(Localization.T("volume_players"), Array.Empty<GUILayoutOption>());
		float num = GUILayout.HorizontalSlider(SettingsManager.CurrentSettings.playersVolume, 0f, 1f, Array.Empty<GUILayoutOption>());
		if (Math.Abs(num - SettingsManager.CurrentSettings.playersVolume) > 0.001f)
		{
			SettingsManager.CurrentSettings.playersVolume = num;
			VoiceManager.UpdatePlayersVolume(num);
			SettingsManager.Save();
		}
		GUILayout.Label(Localization.T("volume_microphone"), Array.Empty<GUILayoutOption>());
		float num2 = GUILayout.HorizontalSlider(SettingsManager.CurrentSettings.selfVolume, 0f, 1f, Array.Empty<GUILayoutOption>());
		if (Math.Abs(num2 - SettingsManager.CurrentSettings.selfVolume) > 0.001f)
		{
			SettingsManager.CurrentSettings.selfVolume = num2;
			VoiceManager.UpdateSelfVolume(num2);
			SettingsManager.Save();
		}
		bool flag = GUILayout.Toggle(SettingsManager.CurrentSettings.hearSelf, Localization.T("hear_myself"), Array.Empty<GUILayoutOption>());
		if (flag != SettingsManager.CurrentSettings.hearSelf)
		{
			SettingsManager.CurrentSettings.hearSelf = flag;
			SettingsManager.Save();
			VoiceManager.StopCapture();
			if (flag)
			{
				VoiceManager.StartCapture(SettingsManager.CurrentSettings.selectedMicIndex);
			}
		}
		GUILayout.Space(8f);
		GUILayout.Label(Localization.T("select_microphone"), Array.Empty<GUILayoutOption>());
		if (GUILayout.Button((VoiceManager.MicDevices.Length != 0) ? VoiceManager.MicDevices[SettingsManager.CurrentSettings.selectedMicIndex] : "No microphone", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) }))
		{
			MicDropdownOpen = !MicDropdownOpen;
		}
		GUILayout.Space(8f);
		GUILayout.Label(Localization.T("keybinds"), Array.Empty<GUILayoutOption>());
		DrawKeybind("open_close_menu", SettingsManager.CurrentSettings.menuToggleKey, delegate(KeyCode k)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			SettingsManager.CurrentSettings.menuToggleKey = k;
		});
		DrawKeybind("push_to_talk", SettingsManager.CurrentSettings.pushToTalkKey, delegate(KeyCode k)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			SettingsManager.CurrentSettings.pushToTalkKey = k;
		});
		GUILayout.Space(8f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(Localization.T("buffer_size"), Array.Empty<GUILayoutOption>());
		int bufferSizeMs = SettingsManager.CurrentSettings.bufferSizeMs;
		int num3 = (int)GUILayout.HorizontalSlider((float)bufferSizeMs, 10f, 100f, Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		GUILayout.Label(string.Format("{0} {1} ms", Localization.T("buffer_current"), num3), Array.Empty<GUILayoutOption>());
		if (num3 != bufferSizeMs)
		{
			SettingsManager.CurrentSettings.bufferSizeMs = num3;
			SettingsManager.Save();
		}
		GUILayout.Space(8f);
		GUILayout.Label(Localization.T("language"), Array.Empty<GUILayoutOption>());
		string[] array = new string[6] { "English", "Russian (Русский)", "Spanish (Español)", "French (Français)", "Chinese (中文)", "Japanese (日本語)" };
		int num4 = Array.IndexOf(array, SettingsManager.CurrentSettings.language);
		if (num4 == -1)
		{
			num4 = 0;
		}
		int num5 = 3;
		int num6 = Mathf.CeilToInt((float)array.Length / (float)num5);
		int num7 = num4;
		for (int i = 0; i < num6; i++)
		{
			int num8 = i * num5;
			int num9 = Mathf.Min(num8 + num5, array.Length);
			string[] array2 = new string[num9 - num8];
			Array.Copy(array, num8, array2, 0, array2.Length);
			int num10 = GUILayout.Toolbar(Array.IndexOf(array2, array[num7]), array2, Array.Empty<GUILayoutOption>());
			if (num10 != Array.IndexOf(array2, array[num7]))
			{
				num7 = num8 + num10;
			}
		}
		if (num7 != num4)
		{
			SettingsManager.CurrentSettings.language = array[num7];
			Localization.SetLanguage(SettingsManager.CurrentSettings.language);
			SpeakingIndicator.UpdateSpeakText();
			SettingsManager.Save();
		}
		if (GUILayout.Button(Localization.T("close"), Array.Empty<GUILayoutOption>()))
		{
			ShowMenu = false;
			MicDropdownOpen = false;
		}
		GUILayout.EndVertical();
		GUI.DragWindow();
	}

	private void DrawKeybind(string labelKey, KeyCode currentKey, Action<KeyCode> onKeyPressed)
	{
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(Localization.T(labelKey), Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(((object)(KeyCode)(ref currentKey)).ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }) && !waitingKey)
		{
			((MonoBehaviour)this).StartCoroutine(WaitForKeyPressed(onKeyPressed));
		}
		GUILayout.EndHorizontal();
	}
}
public class UnityMainThreadDispatcher : MonoBehaviour
{
	private static readonly Queue<Action> actions = new Queue<Action>();

	public static void Enqueue(Action action)
	{
		lock (actions)
		{
			actions.Enqueue(action);
		}
	}

	private void Update()
	{
		lock (actions)
		{
			while (actions.Count > 0)
			{
				actions.Dequeue()();
			}
		}
	}
}
public static class VoiceManager
{
	private static WasapiCapture capture;

	private static SoundInSource soundInSource;

	private static IWaveSource waveSource;

	private static WasapiOut playback;

	private static MMDeviceEnumerator deviceEnum;

	private static string allowedScene;

	private static readonly object lockObj = new object();

	public static readonly List<string> speaking = new List<string>();

	private static bool streaming = false;

	private static int udpReceivePort;

	private static Thread udpReceiveThread;

	private static bool receiving = false;

	private static UdpClient udpClient;

	private static Thread keepAliveThreadSend;

	private static bool keepAliveSendRunning = false;

	private static WasapiOut playersPlayback;

	private static string instanceId;

	private static readonly CancellationTokenSource cts = new CancellationTokenSource();

	public static string[] MicDevices { get; private set; } = Array.Empty<string>();


	public static MMDevice[] CaptureDevices { get; private set; } = Array.Empty<MMDevice>();


	public static void RemoveFromSpeaking(string name)
	{
		lock (lockObj)
		{
			speaking.Remove(name);
		}
	}

	private static async void SendUdpPunch()
	{
		try
		{
			if (!streaming)
			{
				byte[] punch = new byte[1];
				udpClient?.Send(punch, punch.Length, Main.ServerEP);
				await Task.Delay(500);
			}
		}
		catch (Exception ex)
		{
			Exception e = ex;
			Debug.LogWarning((object)("[VoiceChat] UDP punch failed: " + e.Message));
		}
	}

	private static void StartUdpKeepAliveSend()
	{
		if (keepAliveSendRunning)
		{
			return;
		}
		keepAliveSendRunning = true;
		keepAliveThreadSend = new Thread((ThreadStart)async delegate
		{
			while (keepAliveSendRunning)
			{
				await Task.Delay(20000);
				try
				{
					SendUdpPunch();
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("[VoiceChat] KeepAliveSend: " + ex.Message));
				}
			}
		})
		{
			IsBackground = true
		};
		keepAliveThreadSend.Start();
	}

	public static void InitDevices()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		try
		{
			deviceEnum = new MMDeviceEnumerator();
			MMDeviceCollection val = deviceEnum.EnumAudioEndpoints((DataFlow)1, (DeviceState)1);
			List<string> list = new List<string>();
			List<MMDevice> list2 = new List<MMDevice>();
			foreach (MMDevice item in val)
			{
				list.Add(item.FriendlyName);
				list2.Add(item);
			}
			MicDevices = list.ToArray();
			CaptureDevices = list2.ToArray();
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] CSCore: InitDevices failed: " + ex.Message));
			MicDevices = Array.Empty<string>();
			CaptureDevices = Array.Empty<MMDevice>();
		}
	}

	public static void StartCapture(int deviceIndex)
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Expected O, but got Unknown
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		try
		{
			StopCapture();
			if (SettingsManager.CurrentSettings.hearSelf && CaptureDevices.Length != 0 && deviceIndex >= 0 && deviceIndex < CaptureDevices.Length)
			{
				MMDevice device = CaptureDevices[deviceIndex];
				capture = new WasapiCapture
				{
					Device = device
				};
				capture.Initialize();
				soundInSource = new SoundInSource((ISoundIn)(object)capture)
				{
					FillWithZeros = true
				};
				waveSource = FluentExtensions.ToWaveSource(FluentExtensions.ToSampleSource((IWaveSource)(object)soundInSource), 16);
				playback = new WasapiOut();
				playback.Initialize(waveSource);
				playback.Volume = SettingsManager.CurrentSettings.selfVolume;
				capture.Start();
				playback.Play();
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] VoiceManager: StartCapture failed: " + ex.Message));
			StopCapture();
		}
	}

	public static void StopCapture()
	{
		try
		{
			WasapiCapture obj = capture;
			if (obj != null)
			{
				obj.Stop();
			}
		}
		catch
		{
		}
		try
		{
			WasapiOut obj3 = playback;
			if (obj3 != null)
			{
				obj3.Stop();
			}
		}
		catch
		{
		}
		try
		{
			WasapiCapture obj5 = capture;
			if (obj5 != null)
			{
				obj5.Dispose();
			}
		}
		catch
		{
		}
		try
		{
			WasapiOut obj7 = playback;
			if (obj7 != null)
			{
				obj7.Dispose();
			}
		}
		catch
		{
		}
		try
		{
			SoundInSource obj9 = soundInSource;
			if (obj9 != null)
			{
				obj9.Dispose();
			}
		}
		catch
		{
		}
		try
		{
			((IDisposable)waveSource)?.Dispose();
		}
		catch
		{
		}
		capture = null;
		playback = null;
		soundInSource = null;
		waveSource = null;
	}

	public static void SetInstanceId(string instanceid)
	{
		instanceId = instanceid;
	}

	public static async Task StartVoiceStream(CancellationToken token)
	{
		StopVoiceStream();
		streaming = true;
		try
		{
			if (NetworkManager.State != NetworkManager.ConnectionState.Connected)
			{
				Debug.LogWarning((object)"[VoiceChat] TCP connection missing, trying reconnect...");
				if (!(await NetworkManager.Connect()))
				{
					Debug.LogError((object)"[VoiceChat] failed to reconnect tcp.");
					streaming = false;
					return;
				}
			}
			if (udpClient == null)
			{
				udpClient = new UdpClient(0);
				udpReceivePort = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
				udpClient.Client.ReceiveTimeout = 1000;
				udpClient.Client.SendTimeout = 1000;
			}
			await NetworkManager.SendMessage("SPEAK_REQUEST");
			if (!(await NetworkManager.WaitForResponse("SPEAK_OK", 500)))
			{
				Debug.LogError((object)"[VoiceChat] failed to request speak.");
				streaming = false;
				return;
			}
			string localSteamID = SteamUser.GetSteamID().m_SteamID.ToString();
			await NetworkManager.SendMessage($"UDP_INFO|{localSteamID}|{udpReceivePort}|{instanceId}");
			Task.Run(() => SendAudioLoop(token), token);
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] error starting voice stream: " + ex));
			streaming = false;
		}
	}

	public static void StopVoiceStream()
	{
		if (streaming)
		{
			streaming = false;
		}
	}

	public static async Task StartReceiving(CancellationToken token)
	{
		if (receiving)
		{
			return;
		}
		try
		{
			if (udpClient == null)
			{
				udpClient = new UdpClient(0);
			}
			udpReceivePort = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
			receiving = true;
			udpClient.Client.ReceiveTimeout = 1000;
			udpClient.Client.SendTimeout = 1000;
			string steamID = SteamUser.GetSteamID().m_SteamID.ToString();
			await NetworkManager.SendMessage($"UDP_INFO|{steamID}|{udpReceivePort}|{instanceId}");
			StartUdpKeepAliveSend();
			Task.Run(() => ReceiveAudioLoop(token), token);
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] failed to start udp receive: " + ex.Message));
		}
	}

	public static void StopReceiving()
	{
		try
		{
			receiving = false;
			keepAliveSendRunning = false;
			if (keepAliveThreadSend != null)
			{
				try
				{
					keepAliveThreadSend.Join(500);
				}
				catch
				{
				}
				keepAliveThreadSend = null;
			}
			try
			{
				udpClient?.Close();
			}
			catch
			{
			}
			if (udpReceiveThread != null)
			{
				try
				{
					udpReceiveThread.Join(500);
				}
				catch
				{
				}
				udpReceiveThread = null;
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VoiceChat] error stopping udp receive: " + ex.Message));
		}
	}

	private static async Task ReceiveAudioLoop(CancellationToken token)
	{
		IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
		WaveFormat format = new WaveFormat(48000, 16, 1);
		int bufferSize = format.BytesPerSecond * SettingsManager.CurrentSettings.bufferSizeMs / 1000;
		WriteableBufferingSource bufferSource = new WriteableBufferingSource(format, bufferSize)
		{
			FillWithZeros = true
		};
		try
		{
			playersPlayback = new WasapiOut();
			playersPlayback.Initialize((IWaveSource)(object)bufferSource);
			playersPlayback.Volume = SettingsManager.CurrentSettings.playersVolume;
			playersPlayback.Play();
			while (receiving && !token.IsCancellationRequested)
			{
				try
				{
					byte[] data = udpClient.Receive(ref remoteEP);
					if (data != null && data.Length != 0)
					{
						bufferSource.Write(data, 0, data.Length);
					}
					UnityMainThreadDispatcher.Enqueue(delegate
					{
						lock (lockObj)
						{
							foreach (string item in speaking)
							{
								SpeakingIndicator.OnPlayerSpeaking(item);
							}
						}
					});
				}
				catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
				{
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				await Task.Delay(1, token);
			}
		}
		catch (OperationCanceledException)
		{
		}
		catch (Exception ex4)
		{
			Debug.LogError((object)("[VoiceChat] ReceiveAudioLoop fatal: " + ex4));
		}
		finally
		{
			try
			{
				WasapiOut obj = playersPlayback;
				if (obj != null)
				{
					obj.Stop();
				}
			}
			catch
			{
			}
			try
			{
				WasapiOut obj3 = playersPlayback;
				if (obj3 != null)
				{
					obj3.Dispose();
				}
			}
			catch
			{
			}
		}
	}

	private static async Task SendAudioLoop(CancellationToken token)
	{
		WasapiCapture micCapture = null;
		SoundInSource source = null;
		try
		{
			micCapture = new WasapiCapture();
			micCapture.Initialize();
			source = new SoundInSource((ISoundIn)(object)micCapture)
			{
				FillWithZeros = false
			};
			WaveFormat targetFormat = new WaveFormat(48000, 16, 1);
			IWaveSource converted = FluentExtensions.ToWaveSource(FluentExtensions.ChangeSampleRate(FluentExtensions.ToMono(FluentExtensions.ToSampleSource((IWaveSource)(object)source)), targetFormat.SampleRate), 16);
			micCapture.Start();
			byte[] buffer = new byte[((IAudioSource)converted).WaveFormat.BytesPerSecond * SettingsManager.CurrentSettings.bufferSizeMs / 1000];
			while (streaming && !token.IsCancellationRequested)
			{
				int read = ((IReadableAudioSource<byte>)(object)converted).Read(buffer, 0, buffer.Length);
				bool sendData = true;
				if (SettingsManager.CurrentSettings.micMode == MicMode.VoiceActivation)
				{
					float rms = 0f;
					for (int i = 0; i < read && i + 1 < read; i += 2)
					{
						short sample = (short)(buffer[i] | (buffer[i + 1] << 8));
						float f = (float)sample / 32768f;
						rms += f * f;
					}
					if (read > 0)
					{
						rms = Mathf.Sqrt(rms / (float)(read / 2));
					}
					float db = 20f * Mathf.Log10(Mathf.Max(rms, 0.0001f));
					sendData = db >= SettingsManager.CurrentSettings.voiceThresholdDb;
				}
				if (sendData && read > 0)
				{
					try
					{
						udpClient?.Send(buffer, read, Main.ServerEP);
					}
					catch (Exception ex3)
					{
						Exception ex2 = ex3;
						Debug.LogWarning((object)("[VoiceChat] UDP send failed: " + ex2.Message));
					}
				}
				await Task.Delay(10, token);
			}
		}
		catch (OperationCanceledException)
		{
		}
		catch (Exception ex3)
		{
			Exception ex = ex3;
			Debug.LogError((object)("[VoiceChat] udp capture error: " + ex.Message));
		}
		finally
		{
			SoundInSource obj = source;
			if (obj != null)
			{
				obj.Dispose();
			}
			WasapiCapture obj2 = micCapture;
			if (obj2 != null)
			{
				obj2.Dispose();
			}
		}
	}

	public static void RestartUdp()
	{
		StopReceiving();
		keepAliveSendRunning = false;
		if (keepAliveThreadSend != null)
		{
			try
			{
				keepAliveThreadSend.Join(500);
			}
			catch
			{
			}
			keepAliveThreadSend = null;
		}
		try
		{
			udpClient?.Close();
		}
		catch
		{
		}
		udpClient = null;
		receiving = false;
		StartReceiving(cts.Token);
	}

	public static void UpdatePlayersVolume(float volume)
	{
		if (playersPlayback != null)
		{
			playersPlayback.Volume = volume;
		}
	}

	public static void UpdateSelfVolume(float volume)
	{
		if (playback != null)
		{
			playback.Volume = volume;
		}
	}

	public static void AllowScenePlayback(string scene, string name)
	{
		if (scene == "menus")
		{
			return;
		}
		lock (lockObj)
		{
			allowedScene = scene;
			if (!speaking.Contains(name))
			{
				speaking.Add(name);
			}
		}
	}

	public static bool IsAllowed(string scene)
	{
		return allowedScene != null && allowedScene == scene;
	}
}

CSCore.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Configuration;
using System.Reflection;
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.Text;
using System.Threading;
using CSCore.Codecs.AAC;
using CSCore.Codecs.AIFF;
using CSCore.Codecs.DDP;
using CSCore.Codecs.FLAC;
using CSCore.Codecs.FLAC.Metadata;
using CSCore.Codecs.MP1;
using CSCore.Codecs.MP2;
using CSCore.Codecs.MP3;
using CSCore.Codecs.WAV;
using CSCore.Codecs.WMA;
using CSCore.CoreAudioAPI;
using CSCore.DMO;
using CSCore.DMO.Effects;
using CSCore.DSP;
using CSCore.DirectSound;
using CSCore.MediaFoundation;
using CSCore.SoundIn;
using CSCore.SoundOut;
using CSCore.SoundOut.MMInterop;
using CSCore.Streams;
using CSCore.Streams.SampleConverter;
using CSCore.Tags.ID3;
using CSCore.Tags.ID3.Frames;
using CSCore.Utils;
using CSCore.Utils.Buffer;
using CSCore.Win32;

[assembly: CompilationRelaxations(8)]
[assembly: AssemblyTitle("CSCore")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription(".NET Sound Library")]
[assembly: Guid("7939b0f4-fed9-4dcf-bb59-a17505864c55")]
[assembly: AssemblyFileVersion("1.2.1.2")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
[assembly: InternalsVisibleTo("CSCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100237314800493cdf9aabec35955e8928e3d5416ad1d223e8914e0e025ff9095b21bbb696235b9d3886b0edec26107ca0af49c3170fc08d117e8e9265ab371b157f2c2b27843d97c1d312850d10d1272c1d46d18f02ac56f46676cbe7946049b1b344db7154d35788fee27b3d581bd7d43e41813b10fd360a3fbfab9199d9e86a4")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CSCore")]
[assembly: AssemblyCopyright("Florian R.")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.1.2")]
[module: UnverifiableCode]
namespace CSCore
{
	public static class AudioSubTypes
	{
		public static readonly Guid Unknown = new Guid(0, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Pcm = new Guid(1, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Adpcm = new Guid(2, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid IeeeFloat = new Guid(3, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vselp = new Guid(4, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid IbmCvsd = new Guid(5, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid ALaw = new Guid(6, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MuLaw = new Guid(7, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Dts = new Guid(8, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Drm = new Guid(9, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WmaVoice9 = new Guid(10, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid OkiAdpcm = new Guid(16, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DviAdpcm = new Guid(17, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid ImaAdpcm = new Guid(17, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MediaspaceAdpcm = new Guid(18, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid SierraAdpcm = new Guid(19, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid G723Adpcm = new Guid(20, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DigiStd = new Guid(21, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DigiFix = new Guid(22, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DialogicOkiAdpcm = new Guid(23, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MediaVisionAdpcm = new Guid(24, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid CUCodec = new Guid(25, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid YamahaAdpcm = new Guid(32, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid SonarC = new Guid(33, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DspGroupTrueSpeech = new Guid(34, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid EchoSpeechCorporation1 = new Guid(35, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid AudioFileAf36 = new Guid(36, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Aptx = new Guid(37, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid AudioFileAf10 = new Guid(38, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Prosody1612 = new Guid(39, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Lrc = new Guid(40, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DolbyAc2 = new Guid(48, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Gsm610 = new Guid(49, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MsnAudio = new Guid(50, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid AntexAdpcme = new Guid(51, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid ControlResVqlpc = new Guid(52, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DigiReal = new Guid(53, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid DigiAdpcm = new Guid(54, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid ControlResCr10 = new Guid(55, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_NMS_VBXADPCM = new Guid(56, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CS_IMAADPCM = new Guid(57, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ECHOSC3 = new Guid(58, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ROCKWELL_ADPCM = new Guid(59, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ROCKWELL_DIGITALK = new Guid(60, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_XEBEC = new Guid(61, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G721_ADPCM = new Guid(64, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G728_CELP = new Guid(65, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MSG723 = new Guid(66, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Mpeg = new Guid(80, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_RT24 = new Guid(82, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_PAC = new Guid(83, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MpegLayer3 = new Guid(85, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_LUCENT_G723 = new Guid(89, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CIRRUS = new Guid(96, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ESPCM = new Guid(97, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE = new Guid(98, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CANOPUS_ATRAC = new Guid(99, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G726_ADPCM = new Guid(100, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G722_ADPCM = new Guid(101, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DSAT_DISPLAY = new Guid(103, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = new Guid(105, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_AC8 = new Guid(112, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_AC10 = new Guid(113, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_AC16 = new Guid(114, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_AC20 = new Guid(115, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_RT24 = new Guid(116, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_RT29 = new Guid(117, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_RT29HW = new Guid(118, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_VR12 = new Guid(119, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_VR18 = new Guid(120, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_TQ40 = new Guid(121, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SOFTSOUND = new Guid(128, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VOXWARE_TQ60 = new Guid(129, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MSRT24 = new Guid(130, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G729A = new Guid(131, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MVI_MVI2 = new Guid(132, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DF_G726 = new Guid(133, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DF_GSM610 = new Guid(134, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ISIAUDIO = new Guid(136, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ONLIVE = new Guid(137, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SBC24 = new Guid(145, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DOLBY_AC3_SPDIF = new Guid(146, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MEDIASONIC_G723 = new Guid(147, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_PROSODY_8KBPS = new Guid(148, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ZYXEL_ADPCM = new Guid(151, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_PHILIPS_LPCBB = new Guid(152, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_PACKED = new Guid(153, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MALDEN_PHONYTALK = new Guid(160, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Gsm = new Guid(161, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid G729 = new Guid(162, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid G723 = new Guid(163, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Acelp = new Guid(164, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid RawAac = new Guid(255, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_RHETOREX_ADPCM = new Guid(256, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_IRAT = new Guid(257, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VIVO_G723 = new Guid(273, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VIVO_SIREN = new Guid(274, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DIGITAL_G723 = new Guid(291, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SANYO_LD_ADPCM = new Guid(293, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_ACEPLNET = new Guid(304, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_ACELP4800 = new Guid(305, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_ACELP8V3 = new Guid(306, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_G729 = new Guid(307, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_G729A = new Guid(308, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SIPROLAB_KELVIN = new Guid(309, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_G726ADPCM = new Guid(320, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_QUALCOMM_PUREVOICE = new Guid(336, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_QUALCOMM_HALFRATE = new Guid(337, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_TUBGSM = new Guid(341, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_MSAUDIO1 = new Guid(352, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WindowsMediaAudio = new Guid(353, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WindowsMediaAudioProfessional = new Guid(354, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WindowsMediaAudioLosseless = new Guid(355, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WindowsMediaAudioSpdif = new Guid(356, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_UNISYS_NAP_ADPCM = new Guid(368, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_UNISYS_NAP_ULAW = new Guid(369, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_UNISYS_NAP_ALAW = new Guid(370, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_UNISYS_NAP_16K = new Guid(371, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CREATIVE_ADPCM = new Guid(512, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CREATIVE_FASTSPEECH8 = new Guid(514, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CREATIVE_FASTSPEECH10 = new Guid(515, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_UHER_ADPCM = new Guid(528, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_QUARTERDECK = new Guid(544, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ILINK_VC = new Guid(560, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_RAW_SPORT = new Guid(576, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_ESST_AC3 = new Guid(577, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_IPI_HSX = new Guid(592, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_IPI_RPELP = new Guid(593, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_CS2 = new Guid(608, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SONY_SCX = new Guid(624, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_FM_TOWNS_SND = new Guid(768, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_BTV_DIGITAL = new Guid(1024, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_QDESIGN_MUSIC = new Guid(1104, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_VME_VMPCM = new Guid(1664, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_TPC = new Guid(1665, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_OLIGSM = new Guid(4096, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_OLIADPCM = new Guid(4097, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_OLICELP = new Guid(4098, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_OLISBC = new Guid(4099, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_OLIOPR = new Guid(4100, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_LH_CODEC = new Guid(4352, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_NORRIS = new Guid(5120, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = new Guid(5376, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MPEG_ADTS_AAC = new Guid(5632, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MPEG_RAW_AAC = new Guid(5633, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MPEG_LOAS = new Guid(5634, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid NOKIA_MPEG_ADTS_AAC = new Guid(5640, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid NOKIA_MPEG_RAW_AAC = new Guid(5641, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid VODAFONE_MPEG_ADTS_AAC = new Guid(5642, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid VODAFONE_MPEG_RAW_AAC = new Guid(5643, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MPEG_HEAAC = new Guid(5648, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DVM = new Guid(8192, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis1 = new Guid(26447, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis2 = new Guid(26448, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis3 = new Guid(26449, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis1P = new Guid(26479, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis2P = new Guid(26480, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Vorbis3P = new Guid(26481, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_RAW_AAC1 = new Guid(255, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_WMAVOICE9 = new Guid(10, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid Extensible = new Guid(65534, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_DEVELOPMENT = new Guid(65535, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid WAVE_FORMAT_FLAC = new Guid(61868, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);

		public static readonly Guid MediaTypeAudio = new Guid("73647561-0000-0010-8000-00AA00389B71");

		public static AudioEncoding EncodingFromSubType(Guid audioSubType)
		{
			byte[] value = audioSubType.ToByteArray();
			int num = BitConverter.ToInt32(value, 0);
			if (Enum.IsDefined(typeof(AudioEncoding), (short)num))
			{
				return (AudioEncoding)num;
			}
			throw new ArgumentException("Invalid audioSubType.", "audioSubType");
		}

		public static Guid SubTypeFromEncoding(AudioEncoding audioEncoding)
		{
			if (Enum.IsDefined(typeof(AudioEncoding), (short)audioEncoding))
			{
				return new Guid((int)audioEncoding, 0, 16, 128, 0, 0, 170, 0, 56, 155, 113);
			}
			throw new ArgumentException("Invalid encoding.", "audioEncoding");
		}
	}
	public enum AudioEncoding : short
	{
		Unknown = 0,
		Pcm = 1,
		Adpcm = 2,
		IeeeFloat = 3,
		Vselp = 4,
		IbmCvsd = 5,
		ALaw = 6,
		MuLaw = 7,
		Dts = 8,
		Drm = 9,
		WmaVoice9 = 10,
		OkiAdpcm = 16,
		DviAdpcm = 17,
		ImaAdpcm = 17,
		MediaspaceAdpcm = 18,
		SierraAdpcm = 19,
		G723Adpcm = 20,
		DigiStd = 21,
		DigiFix = 22,
		DialogicOkiAdpcm = 23,
		MediaVisionAdpcm = 24,
		CUCodec = 25,
		YamahaAdpcm = 32,
		SonarC = 33,
		DspGroupTrueSpeech = 34,
		EchoSpeechCorporation1 = 35,
		AudioFileAf36 = 36,
		Aptx = 37,
		AudioFileAf10 = 38,
		Prosody1612 = 39,
		Lrc = 40,
		DolbyAc2 = 48,
		Gsm610 = 49,
		MsnAudio = 50,
		AntexAdpcme = 51,
		ControlResVqlpc = 52,
		DigiReal = 53,
		DigiAdpcm = 54,
		ControlResCr10 = 55,
		WAVE_FORMAT_NMS_VBXADPCM = 56,
		WAVE_FORMAT_CS_IMAADPCM = 57,
		WAVE_FORMAT_ECHOSC3 = 58,
		WAVE_FORMAT_ROCKWELL_ADPCM = 59,
		WAVE_FORMAT_ROCKWELL_DIGITALK = 60,
		WAVE_FORMAT_XEBEC = 61,
		WAVE_FORMAT_G721_ADPCM = 64,
		WAVE_FORMAT_G728_CELP = 65,
		WAVE_FORMAT_MSG723 = 66,
		Mpeg = 80,
		WAVE_FORMAT_RT24 = 82,
		WAVE_FORMAT_PAC = 83,
		MpegLayer3 = 85,
		WAVE_FORMAT_LUCENT_G723 = 89,
		WAVE_FORMAT_CIRRUS = 96,
		WAVE_FORMAT_ESPCM = 97,
		WAVE_FORMAT_VOXWARE = 98,
		WAVE_FORMAT_CANOPUS_ATRAC = 99,
		WAVE_FORMAT_G726_ADPCM = 100,
		WAVE_FORMAT_G722_ADPCM = 101,
		WAVE_FORMAT_DSAT_DISPLAY = 103,
		WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 105,
		WAVE_FORMAT_VOXWARE_AC8 = 112,
		WAVE_FORMAT_VOXWARE_AC10 = 113,
		WAVE_FORMAT_VOXWARE_AC16 = 114,
		WAVE_FORMAT_VOXWARE_AC20 = 115,
		WAVE_FORMAT_VOXWARE_RT24 = 116,
		WAVE_FORMAT_VOXWARE_RT29 = 117,
		WAVE_FORMAT_VOXWARE_RT29HW = 118,
		WAVE_FORMAT_VOXWARE_VR12 = 119,
		WAVE_FORMAT_VOXWARE_VR18 = 120,
		WAVE_FORMAT_VOXWARE_TQ40 = 121,
		WAVE_FORMAT_SOFTSOUND = 128,
		WAVE_FORMAT_VOXWARE_TQ60 = 129,
		WAVE_FORMAT_MSRT24 = 130,
		WAVE_FORMAT_G729A = 131,
		WAVE_FORMAT_MVI_MVI2 = 132,
		WAVE_FORMAT_DF_G726 = 133,
		WAVE_FORMAT_DF_GSM610 = 134,
		WAVE_FORMAT_ISIAUDIO = 136,
		WAVE_FORMAT_ONLIVE = 137,
		WAVE_FORMAT_SBC24 = 145,
		WAVE_FORMAT_DOLBY_AC3_SPDIF = 146,
		WAVE_FORMAT_MEDIASONIC_G723 = 147,
		WAVE_FORMAT_PROSODY_8KBPS = 148,
		WAVE_FORMAT_ZYXEL_ADPCM = 151,
		WAVE_FORMAT_PHILIPS_LPCBB = 152,
		WAVE_FORMAT_PACKED = 153,
		WAVE_FORMAT_MALDEN_PHONYTALK = 160,
		Gsm = 161,
		G729 = 162,
		G723 = 163,
		Acelp = 164,
		RawAac = 255,
		WAVE_FORMAT_RHETOREX_ADPCM = 256,
		WAVE_FORMAT_IRAT = 257,
		WAVE_FORMAT_VIVO_G723 = 273,
		WAVE_FORMAT_VIVO_SIREN = 274,
		WAVE_FORMAT_DIGITAL_G723 = 291,
		WAVE_FORMAT_SANYO_LD_ADPCM = 293,
		WAVE_FORMAT_SIPROLAB_ACEPLNET = 304,
		WAVE_FORMAT_SIPROLAB_ACELP4800 = 305,
		WAVE_FORMAT_SIPROLAB_ACELP8V3 = 306,
		WAVE_FORMAT_SIPROLAB_G729 = 307,
		WAVE_FORMAT_SIPROLAB_G729A = 308,
		WAVE_FORMAT_SIPROLAB_KELVIN = 309,
		WAVE_FORMAT_G726ADPCM = 320,
		WAVE_FORMAT_QUALCOMM_PUREVOICE = 336,
		WAVE_FORMAT_QUALCOMM_HALFRATE = 337,
		WAVE_FORMAT_TUBGSM = 341,
		WAVE_FORMAT_MSAUDIO1 = 352,
		WindowsMediaAudio = 353,
		WindowsMediaAudioProfessional = 354,
		WindowsMediaAudioLosseless = 355,
		WindowsMediaAudioSpdif = 356,
		WAVE_FORMAT_UNISYS_NAP_ADPCM = 368,
		WAVE_FORMAT_UNISYS_NAP_ULAW = 369,
		WAVE_FORMAT_UNISYS_NAP_ALAW = 370,
		WAVE_FORMAT_UNISYS_NAP_16K = 371,
		WAVE_FORMAT_CREATIVE_ADPCM = 512,
		WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 514,
		WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 515,
		WAVE_FORMAT_UHER_ADPCM = 528,
		WAVE_FORMAT_QUARTERDECK = 544,
		WAVE_FORMAT_ILINK_VC = 560,
		WAVE_FORMAT_RAW_SPORT = 576,
		WAVE_FORMAT_ESST_AC3 = 577,
		WAVE_FORMAT_IPI_HSX = 592,
		WAVE_FORMAT_IPI_RPELP = 593,
		WAVE_FORMAT_CS2 = 608,
		WAVE_FORMAT_SONY_SCX = 624,
		WAVE_FORMAT_FM_TOWNS_SND = 768,
		WAVE_FORMAT_BTV_DIGITAL = 1024,
		WAVE_FORMAT_QDESIGN_MUSIC = 1104,
		WAVE_FORMAT_VME_VMPCM = 1664,
		WAVE_FORMAT_TPC = 1665,
		WAVE_FORMAT_OLIGSM = 4096,
		WAVE_FORMAT_OLIADPCM = 4097,
		WAVE_FORMAT_OLICELP = 4098,
		WAVE_FORMAT_OLISBC = 4099,
		WAVE_FORMAT_OLIOPR = 4100,
		WAVE_FORMAT_LH_CODEC = 4352,
		WAVE_FORMAT_NORRIS = 5120,
		WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 5376,
		MPEG_ADTS_AAC = 5632,
		MPEG_RAW_AAC = 5633,
		MPEG_LOAS = 5634,
		NOKIA_MPEG_ADTS_AAC = 5640,
		NOKIA_MPEG_RAW_AAC = 5641,
		VODAFONE_MPEG_ADTS_AAC = 5642,
		VODAFONE_MPEG_RAW_AAC = 5643,
		MPEG_HEAAC = 5648,
		WAVE_FORMAT_DVM = 8192,
		Vorbis1 = 26447,
		Vorbis2 = 26448,
		Vorbis3 = 26449,
		Vorbis1P = 26479,
		Vorbis2P = 26480,
		Vorbis3P = 26481,
		WAVE_FORMAT_RAW_AAC1 = 255,
		WAVE_FORMAT_WMAVOICE9 = 10,
		Extensible = -2,
		WAVE_FORMAT_DEVELOPMENT = -1,
		WAVE_FORMAT_FLAC = -3668
	}
	[Flags]
	public enum ChannelMask
	{
		SpeakerFrontLeft = 1,
		SpeakerFrontRight = 2,
		SpeakerFrontCenter = 4,
		SpeakerLowFrequency = 8,
		SpeakerBackLeft = 0x10,
		SpeakerBackRight = 0x20,
		SpeakerFrontLeftOfCenter = 0x40,
		SpeakerFrontRightOfCenter = 0x80,
		SpeakerBackCenter = 0x100,
		SpeakerSideLeft = 0x200,
		SpeakerSideRight = 0x400,
		SpeakerTopCenter = 0x800,
		SpeakerTopFrontLeft = 0x1000,
		SpeakerTopFrontCenter = 0x2000,
		SpeakerTopFrontRight = 0x4000,
		SpeakerTopBackLeft = 0x8000,
		SpeakerTopBackCenter = 0x10000,
		SpeakerTopBackRight = 0x20000
	}
	public static class ChannelMasks
	{
		public const ChannelMask MonoMask = ChannelMask.SpeakerFrontCenter;

		public const ChannelMask StereoMask = ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight;

		public const ChannelMask FiveDotOneWithRearMask = ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight;

		public const ChannelMask FiveDotOneWithSideMask = ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight;

		public const ChannelMask SevenDotOneMask = ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight;
	}
	public static class FluentExtensions
	{
		public static TResult AppendSource<TInput, TResult>(this TInput input, Func<TInput, TResult> func) where TInput : IAudioSource
		{
			return func(input);
		}

		public static TResult AppendSource<TInput, TResult>(this TInput input, Func<TInput, TResult> func, out TResult outputSource) where TInput : IAudioSource
		{
			outputSource = func(input);
			return outputSource;
		}

		public static IWaveSource ChangeSampleRate(this IWaveSource input, int destinationSampleRate)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (destinationSampleRate <= 0)
			{
				throw new ArgumentOutOfRangeException("destinationSampleRate");
			}
			if (input.WaveFormat.SampleRate == destinationSampleRate)
			{
				return input;
			}
			return new DmoResampler(input, destinationSampleRate);
		}

		public static ISampleSource ChangeSampleRate(this ISampleSource input, int destinationSampleRate)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (destinationSampleRate <= 0)
			{
				throw new ArgumentOutOfRangeException("destinationSampleRate");
			}
			if (input.WaveFormat.SampleRate == destinationSampleRate)
			{
				return input;
			}
			return new DmoResampler(input.ToWaveSource(), destinationSampleRate).ToSampleSource();
		}

		public static IWaveSource ToStereo(this IWaveSource input)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (input.WaveFormat.Channels == 2)
			{
				return input;
			}
			if (input.WaveFormat.Channels == 1)
			{
				return new MonoToStereoSource(input.ToSampleSource()).ToWaveSource(input.WaveFormat.BitsPerSample);
			}
			if (input.WaveFormat is WaveFormatExtensible waveFormatExtensible)
			{
				ChannelMask channelMask = waveFormatExtensible.ChannelMask;
				ChannelMatrix matrix = ChannelMatrix.GetMatrix(channelMask, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight);
				return new DmoChannelResampler(input, matrix);
			}
			WaveFormat waveFormat = (WaveFormat)input.WaveFormat.Clone();
			waveFormat.Channels = 2;
			return new DmoResampler(input, waveFormat);
		}

		public static ISampleSource ToStereo(this ISampleSource input)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (input.WaveFormat.Channels == 2)
			{
				return input;
			}
			if (input.WaveFormat.Channels == 1)
			{
				return new MonoToStereoSource(input);
			}
			return input.ToWaveSource().ToStereo().ToSampleSource();
		}

		public static IWaveSource ToMono(this IWaveSource input)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (input.WaveFormat.Channels == 1)
			{
				return input;
			}
			if (input.WaveFormat.Channels == 2)
			{
				return new StereoToMonoSource(input.ToSampleSource()).ToWaveSource(input.WaveFormat.BitsPerSample);
			}
			if (input.WaveFormat is WaveFormatExtensible waveFormatExtensible)
			{
				ChannelMask channelMask = waveFormatExtensible.ChannelMask;
				ChannelMatrix matrix = ChannelMatrix.GetMatrix(channelMask, ChannelMask.SpeakerFrontCenter);
				return new DmoChannelResampler(input, matrix);
			}
			WaveFormat waveFormat = (WaveFormat)input.WaveFormat.Clone();
			waveFormat.Channels = 1;
			return new DmoResampler(input, waveFormat);
		}

		public static ISampleSource ToMono(this ISampleSource input)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (input.WaveFormat.Channels == 1)
			{
				return input;
			}
			if (input.WaveFormat.Channels == 2)
			{
				return new StereoToMonoSource(input);
			}
			return input.ToWaveSource().ToMono().ToSampleSource();
		}

		public static IWaveSource Loop(this IWaveSource input)
		{
			return new LoopStream(input)
			{
				EnableLoop = true
			};
		}

		public static IWaveSource ToWaveSource(this ISampleSource sampleSource, int bits)
		{
			if (sampleSource == null)
			{
				throw new ArgumentNullException("sampleSource");
			}
			return bits switch
			{
				8 => new SampleToPcm8(sampleSource), 
				16 => new SampleToPcm16(sampleSource), 
				24 => new SampleToPcm24(sampleSource), 
				32 => new SampleToIeeeFloat32(sampleSource), 
				_ => throw new ArgumentOutOfRangeException("bits", "Must be 8, 16, 24 or 32 bits."), 
			};
		}

		public static IWaveSource ToWaveSource(this ISampleSource sampleSource)
		{
			if (sampleSource == null)
			{
				throw new ArgumentNullException("sampleSource");
			}
			return new SampleToIeeeFloat32(sampleSource);
		}

		public static ISampleSource ToSampleSource(this IWaveSource waveSource)
		{
			if (waveSource == null)
			{
				throw new ArgumentNullException("waveSource");
			}
			return WaveToSampleBase.CreateConverter(waveSource);
		}

		public static SynchronizedWaveSource<TAudioSource, T> Synchronized<TAudioSource, T>(this TAudioSource audioSource) where TAudioSource : class, IReadableAudioSource<T>
		{
			if (audioSource == null)
			{
				throw new ArgumentNullException("audioSource");
			}
			return new SynchronizedWaveSource<TAudioSource, T>(audioSource);
		}
	}
	public interface IAudioSource : IDisposable
	{
		bool CanSeek { get; }

		WaveFormat WaveFormat { get; }

		long Position { get; set; }

		long Length { get; }
	}
	public interface IWaveSource : IReadableAudioSource<byte>, IAudioSource, IDisposable
	{
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class WaveFormat : ICloneable, IEquatable<WaveFormat>
	{
		private AudioEncoding _encoding;

		private short _channels;

		private int _sampleRate;

		private int _bytesPerSecond;

		private short _blockAlign;

		private short _bitsPerSample;

		private short _extraSize;

		public virtual int Channels
		{
			get
			{
				return _channels;
			}
			protected internal set
			{
				_channels = (short)value;
				UpdateProperties();
			}
		}

		public virtual int SampleRate
		{
			get
			{
				return _sampleRate;
			}
			protected internal set
			{
				_sampleRate = value;
				UpdateProperties();
			}
		}

		public virtual int BytesPerSecond
		{
			get
			{
				return _bytesPerSecond;
			}
			protected internal set
			{
				_bytesPerSecond = value;
			}
		}

		public virtual int BlockAlign
		{
			get
			{
				return _blockAlign;
			}
			protected internal set
			{
				_blockAlign = (short)value;
			}
		}

		public virtual int BitsPerSample
		{
			get
			{
				return _bitsPerSample;
			}
			protected internal set
			{
				_bitsPerSample = (short)value;
				UpdateProperties();
			}
		}

		public virtual int ExtraSize
		{
			get
			{
				return _extraSize;
			}
			protected internal set
			{
				_extraSize = (short)value;
			}
		}

		public virtual int BytesPerSample => BitsPerSample / 8;

		public virtual int BytesPerBlock => BytesPerSample * Channels;

		public virtual AudioEncoding WaveFormatTag
		{
			get
			{
				return _encoding;
			}
			protected internal set
			{
				_encoding = value;
			}
		}

		public WaveFormat()
			: this(44100, 16, 2)
		{
		}

		public WaveFormat(int sampleRate, int bits, int channels)
			: this(sampleRate, bits, channels, AudioEncoding.Pcm)
		{
		}

		public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding)
			: this(sampleRate, bits, channels, encoding, 0)
		{
		}

		public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding, int extraSize)
		{
			if (sampleRate < 1)
			{
				throw new ArgumentOutOfRangeException("sampleRate");
			}
			if (bits < 0)
			{
				throw new ArgumentOutOfRangeException("bits");
			}
			if (channels < 1)
			{
				throw new ArgumentOutOfRangeException("channels", "Number of channels has to be bigger than 0.");
			}
			_sampleRate = sampleRate;
			_bitsPerSample = (short)bits;
			_channels = (short)channels;
			_encoding = encoding;
			_extraSize = (short)extraSize;
			UpdateProperties();
		}

		public long MillisecondsToBytes(double milliseconds)
		{
			long num = (long)((double)BytesPerSecond / 1000.0 * milliseconds);
			return num - num % BlockAlign;
		}

		public double BytesToMilliseconds(long bytes)
		{
			bytes -= bytes % BlockAlign;
			return (double)bytes / (double)BytesPerSecond * 1000.0;
		}

		public virtual bool Equals(WaveFormat other)
		{
			if (Channels == other.Channels && SampleRate == other.SampleRate && BytesPerSecond == other.BytesPerSecond && BlockAlign == other.BlockAlign && BitsPerSample == other.BitsPerSample && ExtraSize == other.ExtraSize)
			{
				return WaveFormatTag == other.WaveFormatTag;
			}
			return false;
		}

		public override string ToString()
		{
			return GetInformation().ToString();
		}

		public virtual object Clone()
		{
			return MemberwiseClone();
		}

		internal virtual void SetWaveFormatTagInternal(AudioEncoding waveFormatTag)
		{
			WaveFormatTag = waveFormatTag;
		}

		internal virtual void SetBitsPerSampleAndFormatProperties(int bitsPerSample)
		{
			BitsPerSample = bitsPerSample;
			UpdateProperties();
		}

		protected internal virtual void UpdateProperties()
		{
			BlockAlign = BitsPerSample / 8 * Channels;
			BytesPerSecond = BlockAlign * SampleRate;
		}

		[DebuggerStepThrough]
		private StringBuilder GetInformation()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("ChannelsAvailable: " + Channels);
			stringBuilder.Append("|SampleRate: " + SampleRate);
			stringBuilder.Append("|Bps: " + BytesPerSecond);
			stringBuilder.Append("|BlockAlign: " + BlockAlign);
			stringBuilder.Append("|BitsPerSample: " + BitsPerSample);
			stringBuilder.Append("|Encoding: " + _encoding);
			return stringBuilder;
		}
	}
}
namespace CSCore.DSP
{
	public class DmoResampler : WaveAggregatorBase
	{
		internal MediaBuffer InputBuffer;

		internal object LockObj = new object();

		internal DmoOutputDataBuffer OutputBuffer;

		internal WaveFormat Outputformat;

		private readonly bool _ignoreBaseStreamPosition;

		internal decimal Ratio;

		internal WMResampler Resampler;

		private bool _disposed;

		private int _quality = 30;

		private byte[] _readBuffer;

		private long _position;

		public override WaveFormat WaveFormat => Outputformat;

		public override long Position
		{
			get
			{
				if (_ignoreBaseStreamPosition)
				{
					return _position;
				}
				return InputToOutput(base.Position);
			}
			set
			{
				base.Position = OutputToInput(value);
				if (_ignoreBaseStreamPosition)
				{
					_position = InputToOutput(base.Position);
				}
			}
		}

		public override long Length => InputToOutput(base.Length);

		public int Quality
		{
			get
			{
				return _quality;
			}
			set
			{
				if (value < 1 || value > 60)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_quality = value;
				using (Resampler.MediaObject.Lock())
				{
					Resampler.ResamplerProps.SetHalfFilterLength(value);
				}
			}
		}

		private static WaveFormat GetWaveFormatWithChangedSampleRate(IWaveSource source, int destSampleRate)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			WaveFormat waveFormat = (WaveFormat)source.WaveFormat.Clone();
			waveFormat.SampleRate = destSampleRate;
			return waveFormat;
		}

		public DmoResampler(IWaveSource source, int destinationSampleRate)
			: this(source, GetWaveFormatWithChangedSampleRate(source, destinationSampleRate))
		{
		}

		public DmoResampler(IWaveSource source, WaveFormat outputFormat)
			: this(source, outputFormat, ignoreBaseStreamPosition: true)
		{
		}

		public DmoResampler(IWaveSource source, WaveFormat outputFormat, bool ignoreBaseStreamPosition)
			: base(source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (outputFormat == null)
			{
				throw new ArgumentNullException("outputFormat");
			}
			Initialize(source.WaveFormat, outputFormat);
			Outputformat = outputFormat;
			_ignoreBaseStreamPosition = ignoreBaseStreamPosition;
		}

		internal void Initialize(WaveFormat inputformat, WaveFormat outputformat)
		{
			Ratio = (decimal)outputformat.BytesPerSecond / (decimal)inputformat.BytesPerSecond;
			lock (LockObj)
			{
				Resampler = new WMResampler();
				MediaObject mediaObject = Resampler.MediaObject;
				if (!mediaObject.SupportsInputFormat(0, inputformat))
				{
					throw new NotSupportedException("Inputformat not supported.");
				}
				mediaObject.SetInputType(0, inputformat);
				if (!mediaObject.SupportsOutputFormat(0, outputformat))
				{
					throw new NotSupportedException("Outputformat not supported.");
				}
				mediaObject.SetOutputType(0, outputformat);
				InputBuffer = new MediaBuffer(inputformat.BytesPerSecond / 2);
				OutputBuffer = new DmoOutputDataBuffer(outputformat.BytesPerSecond / 2);
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			lock (LockObj)
			{
				int num = 0;
				while (num < count)
				{
					MediaObject mediaObject = Resampler.MediaObject;
					if (mediaObject.IsReadyForInput(0))
					{
						int num2 = (int)OutputToInput(count - num);
						_readBuffer = _readBuffer.CheckBuffer(num2);
						int num3 = base.Read(_readBuffer, 0, num2);
						if (num3 <= 0 || _disposed)
						{
							break;
						}
						if (InputBuffer.MaxLength < num3)
						{
							InputBuffer.Dispose();
							InputBuffer = new MediaBuffer(num3);
						}
						InputBuffer.Write(_readBuffer, 0, num3);
						mediaObject.ProcessInput(0, InputBuffer);
						OutputBuffer.Reset();
						MediaBuffer mediaBuffer = (MediaBuffer)OutputBuffer.Buffer;
						if (mediaBuffer.MaxLength < count)
						{
							mediaBuffer.Dispose();
							OutputBuffer.Buffer = new MediaBuffer(count);
						}
						OutputBuffer.Buffer.SetLength(0);
						mediaObject.ProcessOutput(ProcessOutputFlags.None, new DmoOutputDataBuffer[1] { OutputBuffer }, 1);
						if (OutputBuffer.Length > 0)
						{
							OutputBuffer.Read(buffer, offset + num);
							num += OutputBuffer.Length;
						}
					}
				}
				if (_ignoreBaseStreamPosition)
				{
					_position += num;
				}
				return num;
			}
		}

		internal long InputToOutput(long position)
		{
			long num = (long)((decimal)position * Ratio);
			return num - num % Outputformat.BlockAlign;
		}

		internal long OutputToInput(long position)
		{
			long num = (long)((decimal)position / Ratio);
			return num - num % BaseSource.WaveFormat.BlockAlign;
		}

		public void DisposeResamplerOnly()
		{
			bool disposeBaseSource = base.DisposeBaseSource;
			base.DisposeBaseSource = false;
			Dispose();
			base.DisposeBaseSource = disposeBaseSource;
		}

		protected override void Dispose(bool disposing)
		{
			if (!disposing)
			{
				base.DisposeBaseSource = false;
			}
			base.Dispose(disposing);
			DisposeAndReset(ref Resampler);
			OutputBuffer.Dispose();
			DisposeAndReset(ref InputBuffer);
			_readBuffer = null;
			_disposed = true;
		}

		private void DisposeAndReset<T>(ref T obj) where T : class, IDisposable
		{
			if (obj != null)
			{
				try
				{
					obj.Dispose();
				}
				catch (ObjectDisposedException)
				{
				}
				obj = null;
			}
		}
	}
}
namespace CSCore
{
	public interface ISampleSource : IReadableAudioSource<float>, IAudioSource, IDisposable
	{
	}
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public class WaveFormatExtensible : WaveFormat
	{
		internal const int WaveFormatExtensibleExtraSize = 22;

		private short _samplesUnion;

		private ChannelMask _channelMask;

		private Guid _subFormat;

		public int ValidBitsPerSample
		{
			get
			{
				return _samplesUnion;
			}
			protected internal set
			{
				_samplesUnion = (short)value;
			}
		}

		public int SamplesPerBlock
		{
			get
			{
				return _samplesUnion;
			}
			protected internal set
			{
				_samplesUnion = (short)value;
			}
		}

		public ChannelMask ChannelMask
		{
			get
			{
				return _channelMask;
			}
			protected internal set
			{
				_channelMask = value;
			}
		}

		public Guid SubFormat
		{
			get
			{
				return _subFormat;
			}
			protected internal set
			{
				_subFormat = value;
			}
		}

		public static Guid SubTypeFromWaveFormat(WaveFormat waveFormat)
		{
			if (waveFormat == null)
			{
				throw new ArgumentNullException("waveFormat");
			}
			if (waveFormat is WaveFormatExtensible)
			{
				return ((WaveFormatExtensible)waveFormat).SubFormat;
			}
			return AudioSubTypes.SubTypeFromEncoding(waveFormat.WaveFormatTag);
		}

		internal WaveFormatExtensible()
		{
		}

		public WaveFormatExtensible(int sampleRate, int bits, int channels, Guid subFormat)
			: base(sampleRate, bits, channels, AudioEncoding.Extensible, 22)
		{
			_samplesUnion = (short)bits;
			_subFormat = SubTypeFromWaveFormat(this);
			int num = 0;
			for (int i = 0; i < channels; i++)
			{
				num |= 1 << i;
			}
			_channelMask = (ChannelMask)num;
			_subFormat = subFormat;
		}

		public WaveFormatExtensible(int sampleRate, int bits, int channels, Guid subFormat, ChannelMask channelMask)
			: this(sampleRate, bits, channels, subFormat)
		{
			Array values = Enum.GetValues(typeof(ChannelMask));
			int num = 0;
			for (int i = 0; i < values.Length; i++)
			{
				if ((channelMask & (ChannelMask)values.GetValue(i)) == (ChannelMask)values.GetValue(i))
				{
					num++;
				}
			}
			if (channels != num)
			{
				throw new ArgumentException("Channels has to equal the set flags in the channelmask.");
			}
			_channelMask = channelMask;
		}

		public WaveFormat ToWaveFormat()
		{
			return new WaveFormat(SampleRate, BitsPerSample, Channels, AudioSubTypes.EncodingFromSubType(SubFormat));
		}

		public override object Clone()
		{
			return MemberwiseClone();
		}

		internal override void SetWaveFormatTagInternal(AudioEncoding waveFormatTag)
		{
			SubFormat = AudioSubTypes.SubTypeFromEncoding(waveFormatTag);
		}

		[DebuggerStepThrough]
		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder(base.ToString());
			stringBuilder.Append("|SubFormat: " + SubFormat);
			stringBuilder.Append("|ChannelMask: " + ChannelMask);
			return stringBuilder.ToString();
		}
	}
}
namespace CSCore.DSP
{
	public class ChannelMatrix
	{
		private static class Factory
		{
			private class FactoryEntry
			{
				public ChannelMask Input { get; set; }

				public ChannelMask Output { get; set; }

				public ChannelMatrix Matrix { get; set; }

				public FactoryEntry(ChannelMask input, ChannelMask output, ChannelMatrix matrix)
				{
					Input = input;
					Output = output;
					Matrix = matrix;
				}
			}

			private static readonly FactoryEntry[] FactoryEntries = new FactoryEntry[18]
			{
				new FactoryEntry(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, MonoToStereoMatrix),
				new FactoryEntry(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, MonoToFiveDotOneSurroundWithRear),
				new FactoryEntry(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, MonoToFiveDotOneSurroundWithSide),
				new FactoryEntry(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, MonoToSevenDotOneSurround),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontCenter, StereoToMonoMatrix),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, StereoToFiveDotOneSurroundWithRear),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, StereoToFiveDotOneSurroundWithSide),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, StereoToSevenDotOneSurround),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, ChannelMask.SpeakerFrontCenter, FiveDotOneSurroundWithRearToMono),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, FiveDotOneSurroundWithRearToStereo),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, FiveDotOneSurroundWithRearToSevenDotOne),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontCenter, FiveDotOneSurroundWithSideToMono),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, FiveDotOneSurroundWithSideToStereo),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, FiveDotOneSurroundWithSideToSevenDotOne),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontCenter, SevenDotOneSurroundToMono),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, SevenDotOneSurroundToStereo),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, SevenDotOneSurroundToFiveDotOneSurroundWithRear),
				new FactoryEntry(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, SevenDotOneSurroundToFiveDotOneSurroundWithSide)
			};

			public static ChannelMatrix GetMatrix(ChannelMask from, ChannelMask to)
			{
				if (from == to)
				{
					throw new ArgumentException("from must not equal to.");
				}
				FactoryEntry factoryEntry = FactoryEntries.FirstOrDefault((FactoryEntry x) => x.Input == from && x.Output == to);
				if (factoryEntry == null)
				{
					throw new KeyNotFoundException("Could not find a channel matrix for specified channelmasks.");
				}
				return factoryEntry.Matrix;
			}
		}

		public static readonly ChannelMatrix StereoToFiveDotOneSurroundWithRear;

		public static readonly ChannelMatrix FiveDotOneSurroundWithRearToStereo;

		public static readonly ChannelMatrix StereoToFiveDotOneSurroundWithSide;

		public static readonly ChannelMatrix FiveDotOneSurroundWithSideToStereo;

		public static readonly ChannelMatrix StereoToSevenDotOneSurround;

		public static readonly ChannelMatrix SevenDotOneSurroundToStereo;

		public static readonly ChannelMatrix MonoToFiveDotOneSurroundWithRear;

		public static readonly ChannelMatrix FiveDotOneSurroundWithRearToMono;

		public static readonly ChannelMatrix MonoToFiveDotOneSurroundWithSide;

		public static readonly ChannelMatrix FiveDotOneSurroundWithSideToMono;

		public static readonly ChannelMatrix MonoToSevenDotOneSurround;

		public static readonly ChannelMatrix SevenDotOneSurroundToMono;

		public static readonly ChannelMatrix StereoToMonoMatrix;

		public static readonly ChannelMatrix MonoToStereoMatrix;

		public static readonly ChannelMatrix FiveDotOneSurroundWithRearToSevenDotOne;

		public static readonly ChannelMatrix SevenDotOneSurroundToFiveDotOneSurroundWithRear;

		public static readonly ChannelMatrix FiveDotOneSurroundWithSideToSevenDotOne;

		public static readonly ChannelMatrix SevenDotOneSurroundToFiveDotOneSurroundWithSide;

		private readonly ChannelMask _inputMask;

		private readonly ChannelMatrixElement[,] _matrix;

		private readonly ChannelMask _outputMask;

		public ChannelMask InputMask => _inputMask;

		public ChannelMask OutputMask => _outputMask;

		public int Height => _matrix.GetLength(0);

		public int Width => _matrix.GetLength(1);

		public int InputChannelCount => Height;

		public int OutputChannelCount => Width;

		public ChannelMatrixElement this[int input, int output]
		{
			get
			{
				return _matrix[input, output];
			}
			set
			{
				_matrix[input, output] = value;
			}
		}

		public static ChannelMatrix GetMatrix(ChannelMask from, ChannelMask to)
		{
			return Factory.GetMatrix(from, to);
		}

		public static ChannelMatrix GetMatrix(WaveFormat from, WaveFormat to)
		{
			if (from == null)
			{
				throw new ArgumentNullException("from");
			}
			if (to == null)
			{
				throw new ArgumentNullException("to");
			}
			if (TryExtractChannelMask(from, out var channelMask) && TryExtractChannelMask(to, out var channelMask2))
			{
				return GetMatrix(channelMask, channelMask2);
			}
			return null;
		}

		private static bool TryExtractChannelMask(WaveFormat waveFormat, out ChannelMask channelMask)
		{
			channelMask = (ChannelMask)0;
			if (waveFormat is WaveFormatExtensible waveFormatExtensible)
			{
				channelMask = waveFormatExtensible.ChannelMask;
			}
			else if (waveFormat.Channels == 1)
			{
				channelMask = ChannelMask.SpeakerFrontCenter;
			}
			else
			{
				if (waveFormat.Channels != 2)
				{
					return false;
				}
				channelMask = ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight;
			}
			return true;
		}

		internal WaveFormat BuildOutputWaveFormat(IAudioSource audioSource)
		{
			if (audioSource == null)
			{
				throw new ArgumentNullException("source");
			}
			return new WaveFormatExtensible(audioSource.WaveFormat.SampleRate, audioSource.WaveFormat.BitsPerSample, OutputChannelCount, WaveFormatExtensible.SubTypeFromWaveFormat(audioSource.WaveFormat), OutputMask);
		}

		static ChannelMatrix()
		{
			StereoToFiveDotOneSurroundWithRear = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight);
			StereoToFiveDotOneSurroundWithRear.SetMatrix(new float[2, 6]
			{
				{ 0.314f, 0f, 0.222f, 0.031f, 0.268f, 0.164f },
				{ 0f, 0.314f, 0.222f, 0.031f, 0.164f, 0.268f }
			});
			FiveDotOneSurroundWithRearToStereo = StereoToFiveDotOneSurroundWithRear.Flip();
			StereoToFiveDotOneSurroundWithSide = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			StereoToFiveDotOneSurroundWithSide.SetMatrix(new float[2, 6]
			{
				{ 0.32f, 0f, 0.226f, 0.032f, 0.292f, 0.13f },
				{ 0f, 0.32f, 0.226f, 0.032f, 0.13f, 0.292f }
			});
			FiveDotOneSurroundWithSideToStereo = StereoToFiveDotOneSurroundWithSide.Flip();
			StereoToSevenDotOneSurround = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			StereoToSevenDotOneSurround.SetMatrix(new float[2, 8]
			{
				{ 0.222f, 0f, 0.157f, 0.022f, 0.189f, 0.116f, 0.203f, 0.09f },
				{ 0f, 0.222f, 0.157f, 0.022f, 0.116f, 0.189f, 0.09f, 0.203f }
			});
			SevenDotOneSurroundToStereo = StereoToSevenDotOneSurround.Flip();
			MonoToFiveDotOneSurroundWithRear = new ChannelMatrix(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight);
			MonoToFiveDotOneSurroundWithRear.SetMatrix(new float[1, 6] { { 0.192f, 0.192f, 0.192f, 0.038f, 0.192f, 0.192f } });
			FiveDotOneSurroundWithRearToMono = MonoToFiveDotOneSurroundWithRear.Flip();
			MonoToFiveDotOneSurroundWithSide = new ChannelMatrix(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			MonoToFiveDotOneSurroundWithSide.SetMatrix(new float[1, 6] { { 0.192f, 0.192f, 0.192f, 0.038f, 0.192f, 0.192f } });
			FiveDotOneSurroundWithSideToMono = MonoToFiveDotOneSurroundWithSide.Flip();
			MonoToSevenDotOneSurround = new ChannelMatrix(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			MonoToSevenDotOneSurround.SetMatrix(new float[1, 8] { { 0.139f, 0.139f, 0.139f, 0.028f, 0.139f, 0.139f, 0.139f, 0.139f } });
			SevenDotOneSurroundToMono = MonoToSevenDotOneSurround.Flip();
			FiveDotOneSurroundWithRearToSevenDotOne = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			FiveDotOneSurroundWithRearToSevenDotOne.SetMatrix(new float[6, 8]
			{
				{ 0.518f, 0f, 0f, 0f, 0f, 0f, 0.189f, 0f },
				{ 0f, 0.518f, 0f, 0f, 0f, 0f, 0f, 0.189f },
				{ 0f, 0f, 0.518f, 0f, 0f, 0f, 0f, 0f },
				{ 0f, 0f, 0f, 0.518f, 0f, 0f, 0f, 0f },
				{ 0f, 0f, 0f, 0f, 0.518f, 0f, 0.482f, 0f },
				{ 0f, 0f, 0f, 0f, 0f, 0.518f, 0f, 0.482f }
			});
			SevenDotOneSurroundToFiveDotOneSurroundWithRear = FiveDotOneSurroundWithRearToSevenDotOne.Flip();
			FiveDotOneSurroundWithSideToSevenDotOne = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight | ChannelMask.SpeakerFrontCenter | ChannelMask.SpeakerLowFrequency | ChannelMask.SpeakerBackLeft | ChannelMask.SpeakerBackRight | ChannelMask.SpeakerSideLeft | ChannelMask.SpeakerSideRight);
			FiveDotOneSurroundWithSideToSevenDotOne.SetMatrix(new float[6, 8]
			{
				{ 0.447f, 0f, 0f, 0f, 0f, 0f, 0f, 0f },
				{ 0f, 0.447f, 0f, 0f, 0f, 0f, 0f, 0f },
				{ 0f, 0f, 0.447f, 0f, 0f, 0f, 0f, 0f },
				{ 0f, 0f, 0f, 0.447f, 0f, 0f, 0f, 0f },
				{ 0f, 0f, 0f, 0f, 0.429f, 0.124f, 0.447f, 0f },
				{ 0f, 0f, 0f, 0f, 0.124f, 0.429f, 0f, 0.447f }
			});
			SevenDotOneSurroundToFiveDotOneSurroundWithSide = FiveDotOneSurroundWithSideToSevenDotOne.Flip();
			StereoToMonoMatrix = new ChannelMatrix(ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight, ChannelMask.SpeakerFrontCenter);
			StereoToMonoMatrix.SetMatrix(new float[2, 1]
			{
				{ 0.5f },
				{ 0.5f }
			});
			MonoToStereoMatrix = new ChannelMatrix(ChannelMask.SpeakerFrontCenter, ChannelMask.SpeakerFrontLeft | ChannelMask.SpeakerFrontRight);
			MonoToStereoMatrix.SetMatrix(new float[1, 2] { { 1f, 1f } });
		}

		public ChannelMatrix(ChannelMask inputMask, ChannelMask outputMask)
		{
			_inputMask = inputMask;
			_outputMask = outputMask;
			if (inputMask <= (ChannelMask)0)
			{
				throw new ArgumentException("Invalid inputMask");
			}
			if (outputMask <= (ChannelMask)0)
			{
				throw new ArgumentException("Invalid outputMask");
			}
			_matrix = new ChannelMatrixElement[GetValuesOfChannelMask(inputMask).Length, GetValuesOfChannelMask(outputMask).Length];
			for (int i = 0; i < Width; i++)
			{
				for (int j = 0; j < Height; j++)
				{
					_matrix[j, i] = new ChannelMatrixElement(GetValuesOfChannelMask(inputMask)[j], GetValuesOfChannelMask(outputMask)[i]);
				}
			}
		}

		public void SetMatrix(float[,] matrix)
		{
			if (matrix == null)
			{
				throw new ArgumentException("matrix");
			}
			if (matrix.GetLength(1) != Width)
			{
				throw new ArgumentException("Matrix has to have a width of " + Width);
			}
			if (matrix.GetLength(0) != Height)
			{
				throw new ArgumentException("Matrix has to have a height of " + Height);
			}
			for (int i = 0; i < Width; i++)
			{
				for (int j = 0; j < Height; j++)
				{
					this[j, i].Value = matrix[j, i];
				}
			}
		}

		public float[] GetOneDimensionalMatrix()
		{
			List<float> list = new List<float>();
			for (int i = 0; i < Width; i++)
			{
				for (int j = 0; j < Height; j++)
				{
					list.Add(this[j, i].Value);
				}
			}
			return list.ToArray();
		}

		public ChannelMatrix Flip()
		{
			ChannelMatrix channelMatrix = new ChannelMatrix(OutputMask, InputMask);
			for (int i = 0; i < OutputChannelCount; i++)
			{
				for (int j = 0; j < InputChannelCount; j++)
				{
					ChannelMatrixElement channelMatrixElement = this[j, i];
					channelMatrix[i, j] = new ChannelMatrixElement(channelMatrixElement.OutputChannel, channelMatrixElement.InputChannel)
					{
						Value = channelMatrixElement.Value
					};
				}
			}
			return channelMatrix;
		}

		private static ChannelMask[] GetValuesOfChannelMask(ChannelMask channelMask)
		{
			Array values = Enum.GetValues(typeof(ChannelMask));
			List<ChannelMask> list = new List<ChannelMask>();
			for (int i = 0; i < values.Length; i++)
			{
				if ((channelMask & (ChannelMask)values.GetValue(i)) == (ChannelMask)values.GetValue(i))
				{
					list.Add((ChannelMask)values.GetValue(i));
				}
			}
			return list.ToArray();
		}
	}
}
namespace CSCore.Streams
{
	public sealed class MonoToStereoSource : SampleAggregatorBase
	{
		private float[] _buffer;

		private readonly WaveFormat _waveFormat;

		public override long Position
		{
			get
			{
				return base.Position * 2;
			}
			set
			{
				value -= value % WaveFormat.BlockAlign;
				base.Position = value / 2;
			}
		}

		public override long Length => base.Length * 2;

		public override WaveFormat WaveFormat => _waveFormat;

		public MonoToStereoSource(ISampleSource source)
			: base(source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source.WaveFormat.Channels != 1)
			{
				throw new ArgumentException("The WaveFormat of the source has be a mono format (one channel).", "source");
			}
			_waveFormat = new WaveFormat(source.WaveFormat.SampleRate, 32, 2, AudioEncoding.IeeeFloat);
		}

		public override int Read(float[] buffer, int offset, int count)
		{
			int num = count / 2;
			_buffer = _buffer.CheckBuffer(num);
			int num2 = offset;
			int num3 = base.Read(_buffer, 0, num);
			for (int i = 0; i < num3; i++)
			{
				buffer[num2++] = _buffer[i];
				buffer[num2++] = _buffer[i];
			}
			return num3 * 2;
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			_buffer = null;
		}
	}
}
namespace CSCore.DSP
{
	public class DmoChannelResampler : DmoResampler
	{
		private readonly ChannelMatrix _channelMatrix;

		public ChannelMatrix ChannelMatrix => _channelMatrix;

		public DmoChannelResampler(IWaveSource source, ChannelMatrix channelMatrix)
			: this(source, channelMatrix, source.WaveFormat.SampleRate)
		{
		}

		public DmoChannelResampler(IWaveSource source, ChannelMatrix channelMatrix, WaveFormat outputFormat)
			: base(source, outputFormat)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (channelMatrix == null)
			{
				throw new ArgumentNullException("channelMatrix");
			}
			if (outputFormat == null)
			{
				throw new ArgumentNullException("outputFormat");
			}
			if (source.WaveFormat.Channels != channelMatrix.InputChannelCount)
			{
				throw new ArgumentException("The number of channels of the source has to be equal to the number of input channels specified by the channelMatrix.");
			}
			WaveFormatExtensible inputformat = new WaveFormatExtensible(source.WaveFormat.SampleRate, source.WaveFormat.BitsPerSample, source.WaveFormat.Channels, WaveFormatExtensible.SubTypeFromWaveFormat(source.WaveFormat), channelMatrix.InputMask);
			Outputformat = new WaveFormatExtensible(outputFormat.SampleRate, outputFormat.BitsPerSample, outputFormat.Channels, WaveFormatExtensible.SubTypeFromWaveFormat(outputFormat), channelMatrix.OutputMask);
			Initialize(inputformat, Outputformat);
			_channelMatrix = channelMatrix;
			CommitChannelMatrixChanges();
		}

		public DmoChannelResampler(IWaveSource source, ChannelMatrix channelMatrix, int destinationSampleRate)
			: this(source, channelMatrix, GetOutputWaveFormat(source, destinationSampleRate, channelMatrix))
		{
		}

		private static WaveFormat GetOutputWaveFormat(IWaveSource source, int sampleRate, ChannelMatrix channelMatrix)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (channelMatrix == null)
			{
				throw new ArgumentNullException("channelMatrix");
			}
			WaveFormat waveFormat = channelMatrix.BuildOutputWaveFormat(source);
			waveFormat.SampleRate = sampleRate;
			return waveFormat;
		}

		public void CommitChannelMatrixChanges()
		{
			using (Resampler.MediaObject.Lock())
			{
				Resampler.MediaObject.SetOutputType(0, Resampler.MediaObject.GetOutputCurrentType(0), SetTypeFlags.None);
				Resampler.ResamplerProps.SetUserChannelMtx(_channelMatrix.GetOneDimensionalMatrix());
			}
		}
	}
}
namespace CSCore.Streams
{
	public class StereoToMonoSource : SampleAggregatorBase
	{
		private readonly WaveFormat _waveFormat;

		private float[] _buffer;

		public override long Position
		{
			get
			{
				return BaseSource.Position / 2;
			}
			set
			{
				value -= value % WaveFormat.BlockAlign;
				BaseSource.Position = value * 2;
			}
		}

		public override long Length => BaseSource.Length / 2;

		public override WaveFormat WaveFormat => _waveFormat;

		public StereoToMonoSource(ISampleSource source)
			: base(source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source.WaveFormat.Channels != 2)
			{
				throw new ArgumentException("The WaveFormat of the source has be a stereo format (two channels).", "source");
			}
			_waveFormat = new WaveFormat(source.WaveFormat.SampleRate, 32, 1, AudioEncoding.IeeeFloat);
		}

		public unsafe override int Read(float[] buffer, int offset, int count)
		{
			_buffer = _buffer.CheckBuffer(count * 2);
			int num = BaseSource.Read(_buffer, 0, count * 2);
			fixed (float* ptr = buffer)
			{
				float* ptr2 = ptr + offset;
				for (int i = 0; i < num - 1; i += 2)
				{
					*(ptr2++) = (_buffer[i] + _buffer[i + 1]) / 2f;
				}
			}
			return num / 2;
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			_buffer = null;
		}
	}
	public class LoopStream : WaveAggregatorBase
	{
		private bool _enableLoop = true;

		private bool _raisedStreamFinishedEvent;

		public bool EnableLoop
		{
			get
			{
				return _enableLoop;
			}
			set
			{
				_enableLoop = value;
			}
		}

		public event EventHandler StreamFinished;

		public LoopStream(IWaveSource source)
			: base(source)
		{
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			int i;
			int num;
			for (i = base.Read(buffer, offset, count); i < count; i += num)
			{
				num = base.Read(buffer, offset + i, count - i);
				if (num == 0)
				{
					EventHandler streamFinished = this.StreamFinished;
					if (streamFinished != null && !_raisedStreamFinishedEvent)
					{
						streamFinished(this, EventArgs.Empty);
						_raisedStreamFinishedEvent = true;
					}
					if (!EnableLoop)
					{
						break;
					}
					Position = 0L;
				}
				else
				{
					_raisedStreamFinishedEvent = false;
				}
			}
			return i;
		}
	}
}
namespace CSCore.Streams.SampleConverter
{
	public class SampleToPcm8 : SampleToWaveBase
	{
		public SampleToPcm8(ISampleSource source)
			: base(source, 8, AudioEncoding.Pcm)
		{
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			Buffer = Buffer.CheckBuffer(count);
			int num = Source.Read(Buffer, 0, count);
			for (int i = offset; i < num; i++)
			{
				byte b = (byte)((Buffer[i] + 1f) * 128f);
				buffer[i] = b;
			}
			return num;
		}
	}
	public class SampleToPcm16 : SampleToWaveBase
	{
		public SampleToPcm16(ISampleSource source)
			: base(source, 16, AudioEncoding.Pcm)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			Buffer = Buffer.CheckBuffer(count / 2);
			int num = Source.Read(Buffer, 0, count / 2);
			int num2 = offset;
			for (int i = 0; i < num; i++)
			{
				short value = (short)(Buffer[i] * 32767f);
				byte[] bytes = BitConverter.GetBytes(value);
				buffer[num2++] = bytes[0];
				buffer[num2++] = bytes[1];
			}
			return num * 2;
		}
	}
	public class SampleToPcm24 : SampleToWaveBase
	{
		public SampleToPcm24(ISampleSource source)
			: base(source, 24, AudioEncoding.Pcm)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
		}

		public unsafe override int Read(byte[] buffer, int offset, int count)
		{
			int num = count / 3;
			Buffer = Buffer.CheckBuffer(num);
			int num2 = Source.Read(Buffer, 0, num);
			int num3 = offset;
			for (int i = 0; i < num2; i++)
			{
				uint num4 = (uint)(Buffer[i] * 8388608f);
				byte* ptr = (byte*)(&num4);
				buffer[num3++] = *ptr;
				buffer[num3++] = ptr[1];
				buffer[num3++] = ptr[2];
			}
			return num2 * 3;
		}
	}
	public class SampleToIeeeFloat32 : SampleToWaveBase
	{
		public SampleToIeeeFloat32(ISampleSource source)
			: base(source, 32, AudioEncoding.IeeeFloat)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			Buffer = Buffer.CheckBuffer(count / 4);
			int num = Source.Read(Buffer, offset / 4, count / 4);
			System.Buffer.BlockCopy(Buffer, 0, buffer, offset, num * 4);
			return num * 4;
		}
	}
	public abstract class WaveToSampleBase : ISampleSource, IReadableAudioSource<float>, IAudioSource, IDisposable
	{
		private readonly WaveFormat _waveFormat;

		protected internal IWaveSource Source;

		protected internal byte[] Buffer;

		public WaveFormat WaveFormat => _waveFormat;

		public long Position
		{
			get
			{
				if (!CanSeek)
				{
					return 0L;
				}
				return Source.Position / Source.WaveFormat.BytesPerSample;
			}
			set
			{
				if (CanSeek)
				{
					value -= value % WaveFormat.BlockAlign;
					Source.Position = value * Source.WaveFormat.BytesPerSample;
					return;
				}
				throw new InvalidOperationException();
			}
		}

		public long Length
		{
			get
			{
				if (!CanSeek || Source.Length == 0L)
				{
					return 0L;
				}
				return Source.Length / Source.WaveFormat.BytesPerSample;
			}
		}

		public bool CanSeek => Source.CanSeek;

		protected WaveToSampleBase(IWaveSource source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			Source = source;
			_waveFormat = (WaveFormat)source.WaveFormat.Clone();
			_waveFormat.BitsPerSample = 32;
			_waveFormat.SetWaveFormatTagInternal(AudioEncoding.IeeeFloat);
		}

		public abstract int Read(float[] buffer, int offset, int count);

		public void Dispose()
		{
			Dispose(disposing: true);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (Source != null)
			{
				Source.Dispose();
				Source = null;
			}
		}

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

		public static ISampleSource CreateConverter(IWaveSource source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			int bitsPerSample = source.WaveFormat.BitsPerSample;
			if (source.WaveFormat.IsPCM())
			{
				return bitsPerSample switch
				{
					8 => new Pcm8BitToSample(source), 
					16 => new Pcm16BitToSample(source), 
					24 => new Pcm24BitToSample(source), 
					32 => new Pcm32BitToSample(source), 
					_ => throw new NotSupportedException("Waveformat is not supported. Invalid BitsPerSample value."), 
				};
			}
			if (source.WaveFormat.IsIeeeFloat() && bitsPerSample == 32)
			{
				return new IeeeFloatToSample(source);
			}
			throw new NotSupportedException("Waveformat is not supported. Invalid WaveformatTag.");
		}
	}
}
namespace CSCore.Streams
{
	public class SynchronizedWaveSource<TBaseSource, T> : IAggregator<T, TBaseSource>, IReadableAudioSource<T>, IAudioSource, IDisposable where TBaseSource : class, IReadableAudioSource<T>
	{
		private readonly object _lockObj = new object();

		private TBaseSource _baseSource;

		private bool _disposed;

		public WaveFormat WaveFormat
		{
			get
			{
				lock (_lockObj)
				{
					return BaseSource.WaveFormat;
				}
			}
		}

		public long Position
		{
			get
			{
				lock (_lockObj)
				{
					return BaseSource.Position;
				}
			}
			set
			{
				lock (_lockObj)
				{
					value -= value % WaveFormat.BlockAlign;
					BaseSource.Position = value;
				}
			}
		}

		public long Length
		{
			get
			{
				lock (_lockObj)
				{
					return BaseSource.Length;
				}
			}
		}

		public bool CanSeek
		{
			get
			{
				lock (_lockObj)
				{
					return BaseSource.CanSeek;
				}
			}
		}

		public TBaseSource BaseSource
		{
			get
			{
				lock (_lockObj)
				{
					return _baseSource;
				}
			}
			set
			{
				lock (_lockObj)
				{
					if (value == null)
					{
						throw new ArgumentNullException("value");
					}
					_baseSource = value;
				}
			}
		}

		public SynchronizedWaveSource(TBaseSource baseWaveSource)
		{
			BaseSource = baseWaveSource;
		}

		public int Read(T[] buffer, int offset, int count)
		{
			lock (_lockObj)
			{
				return BaseSource.Read(buffer, offset, count);
			}
		}

		public static explicit operator TBaseSource(SynchronizedWaveSource<TBaseSource, T> synchronizedWaveSource)
		{
			if (synchronizedWaveSource == null)
			{
				throw new ArgumentNullException("synchronizedWaveSource");
			}
			return synchronizedWaveSource.BaseSource;
		}

		protected void Dispose(bool disposing)
		{
			lock (_lockObj)
			{
				if (BaseSource != null)
				{
					BaseSource.Dispose();
				}
				_baseSource = null;
			}
		}

		public void Dispose()
		{
			lock (_lockObj)
			{
				if (!_disposed)
				{
					_disposed = true;
					Dispose(disposing: true);
					GC.SuppressFinalize(this);
				}
			}
		}

		~SynchronizedWaveSource()
		{
			lock (_lockObj)
			{
				Dispose(disposing: false);
			}
		}
	}
}
namespace CSCore
{
	public interface IReadableAudioSource<in T> : IAudioSource, IDisposable
	{
		int Read(T[] buffer, int offset, int count);
	}
	public interface IWriteable
	{
		void Write(byte[] buffer, int offset, int count);
	}
	public enum MmResult
	{
		NoError = 0,
		Error = 1,
		BadDevice = 2,
		NotEnabled = 3,
		Allocated = 4,
		InvalidHandle = 5,
		NoDriver = 6,
		NoMemory = 7,
		NotSupported = 8,
		BadErrorNumber = 9,
		InvalidFlag = 10,
		InvalidParameter = 11,
		HandleBusy = 12,
		InvalidAlias = 13,
		BadDatabase = 14,
		KeyNotFound = 15,
		ReadError = 16,
		WriteError = 17,
		DeleteError = 18,
		ValueNotFound = 19,
		NoDriverCallback = 20,
		MoreData = 21,
		BadFormat = 32,
		StillPlaying = 33,
		Unprepared = 34,
		Synchronous = 35
	}
	public class StoppedEventArgs : EventArgs
	{
		private readonly Exception _exception;

		public virtual bool HasError => _exception != null;

		public virtual Exception Exception => _exception;

		public StoppedEventArgs()
			: this(null)
		{
		}

		public StoppedEventArgs(Exception exception)
		{
			_exception = exception;
		}
	}
	public abstract class TimeConverter
	{
		internal class _WaveSourceTimeConverter : TimeConverter
		{
			public override long ToRawElements(WaveFormat waveFormat, TimeSpan timeSpan)
			{
				return waveFormat.MillisecondsToBytes(timeSpan.TotalMilliseconds);
			}

			public override TimeSpan ToTimeSpan(WaveFormat waveFormat, long rawElements)
			{
				return TimeSpan.FromMilliseconds(waveFormat.BytesToMilliseconds(rawElements));
			}
		}

		internal class _SampleSourceTimeConverter : TimeConverter
		{
			public override long ToRawElements(WaveFormat waveFormat, TimeSpan timeSpan)
			{
				return waveFormat.MillisecondsToBytes(timeSpan.TotalMilliseconds) / waveFormat.BytesPerSample;
			}

			public override TimeSpan ToTimeSpan(WaveFormat waveFormat, long rawElements)
			{
				return TimeSpan.FromMilliseconds(waveFormat.BytesToMilliseconds(rawElements * waveFormat.BytesPerSample));
			}
		}

		public static readonly TimeConverter SampleSourceTimeConverter = new _SampleSourceTimeConverter();

		public static readonly TimeConverter WaveSourceTimeConverter = new _WaveSourceTimeConverter();

		public abstract long ToRawElements(WaveFormat waveFormat, TimeSpan timeSpan);

		public abstract TimeSpan ToTimeSpan(WaveFormat waveFormat, long rawElements);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class TimeConverterAttribute : Attribute
	{
		public Type TimeConverterType { get; private set; }

		public object[] Args { get; set; }

		public bool ForceNewInstance { get; set; }

		public TimeConverterAttribute(Type timeConverterType)
		{
			if ((object)timeConverterType == null)
			{
				throw new ArgumentNullException("timeConverterType");
			}
			if (!typeof(TimeConverter).IsAssignableFrom(timeConverterType))
			{
				throw new ArgumentException("Specified type is no time converter.", "timeConverterType");
			}
			TimeConverterType = timeConverterType;
		}
	}
	public sealed class TimeConverterFactory
	{
		private class CacheItem
		{
			public TimeConverter TimeConverter { get; set; }

			public TimeConverterAttribute TimeConverterAttribute { get; set; }

			public bool CreateNewInstance { get; set; }

			public TimeConverter GetTimeConverter()
			{
				if (CreateNewInstance)
				{
					return (TimeConverter)Activator.CreateInstance(TimeConverterAttribute.TimeConverterType, TimeConverterAttribute.Args);
				}
				return TimeConverter;
			}
		}

		private static readonly TimeConverterFactory _instance = new TimeConverterFactory();

		private readonly Dictionary<Type, TimeConverter> _timeConverters;

		private readonly Dictionary<Type, CacheItem> _cache;

		public static TimeConverterFactory Instance => _instance;

		private TimeConverterFactory()
		{
			_timeConverters = new Dictionary<Type, TimeConverter>();
			_cache = new Dictionary<Type, CacheItem>();
			RegisterTimeConverterForSourceType<IWaveSource>(TimeConverter.WaveSourceTimeConverter);
			RegisterTimeConverterForSourceType<ISampleSource>(TimeConverter.SampleSourceTimeConverter);
		}

		public void RegisterTimeConverterForSourceType<TSource>(TimeConverter timeConverter) where TSource : IAudioSource
		{
			if (timeConverter == null)
			{
				throw new ArgumentNullException("timeConverter");
			}
			Type typeFromHandle = typeof(TSource);
			if (_timeConverters.ContainsKey(typeFromHandle))
			{
				throw new ArgumentException("A timeconverter for the same source type got already registered.");
			}
			_timeConverters.Add(typeFromHandle, timeConverter);
		}

		public void UnregisterTimeConverter<TSource>() where TSource : IAudioSource
		{
			Type typeFromHandle = typeof(TSource);
			if (!_timeConverters.ContainsKey(typeFromHandle))
			{
				throw new ArgumentException("There is no timeconverter registered for the specified source type.");
			}
			_timeConverters.Remove(typeFromHandle);
		}

		public TimeConverter GetTimeConverterForSource<TSource>(TSource source) where TSource : class, IAudioSource
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return GetTimeConverterForSourceType(source.GetType());
		}

		public TimeConverter GetTimeConverterForSource<TSource>() where TSource : IAudioSource
		{
			return GetTimeConverterForSourceType(typeof(TSource));
		}

		public TimeConverter GetTimeConverterForSourceType(Type sourceType)
		{
			if ((object)sourceType == null)
			{
				throw new ArgumentNullException("sourceType");
			}
			if (!typeof(IAudioSource).IsAssignableFrom(sourceType))
			{
				throw new ArgumentException("Specified type is no AudioSource.", "sourceType");
			}
			if (_cache.ContainsKey(sourceType))
			{
				return _cache[sourceType].GetTimeConverter();
			}
			TimeConverterAttribute timeConverterAttribute = sourceType.GetCustomAttributes(typeof(TimeConverterAttribute), inherit: false).FirstOrDefault() as TimeConverterAttribute;
			TimeConverter timeConverter = null;
			try
			{
				if (timeConverterAttribute == null)
				{
					Type[] array = (from x in GetTypes(sourceType)
						where _timeConverters.ContainsKey(x)
						select x).ToArray();
					if (array.Length == 1)
					{
						timeConverter = _timeConverters[array.First()];
						return timeConverter;
					}
					if (array.Length == 0)
					{
						throw new ArgumentException("No registered time converter for the specified source type was found.");
					}
					throw new ArgumentException("Multiple possible time converters, for the specified source type, were found. Specify which time converter to use, through the TimeConverterAttribute.");
				}
				Type timeConverterType = timeConverterAttribute.TimeConverterType;
				timeConverter = (TimeConverter)Activator.CreateInstance(timeConverterType, timeConverterAttribute.Args);
				return timeConverter;
			}
			finally
			{
				if (timeConverter != null)
				{
					CacheItem value = ((timeConverterAttribute != null) ? new CacheItem
					{
						CreateNewInstance = timeConverterAttribute.ForceNewInstance,
						TimeConverterAttribute = timeConverterAttribute,
						TimeConverter = (timeConverterAttribute.ForceNewInstance ? null : timeConverter)
					} : new CacheItem
					{
						CreateNewInstance = false,
						TimeConverter = timeConverter
					});
					_cache[sourceType] = value;
				}
			}
		}

		public void ClearCache()
		{
			_cache.Clear();
		}

		private IEnumerable<Type> GetTypes(Type type)
		{
			if ((object)type.BaseType != typeof(object))
			{
				return Enumerable.Repeat(type.BaseType, 1).Concat<Type>(type.GetInterfaces()).Concat(GetTypes(type.BaseType))
					.Distinct();
			}
			return type.GetInterfaces();
		}
	}
	public interface ISampleAggregator : ISampleSource, IReadableAudioSource<float>, IAudioSource, IDisposable, IAggregator<float, ISampleSource>
	{
	}
	public interface IAggregator<in T, out TAggregator> : IReadableAudioSource<T>, IAudioSource, IDisposable where TAggregator : IReadableAudioSource<T>
	{
		TAggregator BaseSource { get; }
	}
	public interface IWaveAggregator : IWaveSource, IReadableAudioSource<byte>, IAudioSource, IDisposable, IAggregator<byte, IWaveSource>
	{
	}
	[Serializable]
	public class MmException : Exception
	{
		public MmResult Result { get; private set; }

		[Obsolete("Use the Function property instead.")]
		public string Target { get; private set; }

		public string Function => Target;

		public static void Try(MmResult result, string function)
		{
			if (result != 0)
			{
				throw new MmException(result, function);
			}
		}

		public MmException(MmResult result, string function)
		{
			Result = result;
			Target = function;
		}

		public MmException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			Target = info.GetString("Target");
			Result = (MmResult)info.GetInt32("Result");
		}

		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			base.GetObjectData(info, context);
			info.AddValue("Target", Target);
			info.AddValue("Result", (int)Result);
		}
	}
	public class SampleAggregatorBase : ISampleAggregator, ISampleSource, IReadableAudioSource<float>, IAudioSource, IDisposable, IAggregator<float, ISampleSource>
	{
		private bool _disposed;

		private ISampleSource _baseSource;

		public virtual WaveFormat WaveFormat => BaseSource.WaveFormat;

		public virtual long Position
		{
			get
			{
				if (!CanSeek)
				{
					return 0L;
				}
				return BaseSource.Position;
			}
			set
			{
				if (CanSeek)
				{
					value -= value % WaveFormat.BlockAlign;
					BaseSource.Position = value;
					return;
				}
				throw new InvalidOperationException("Underlying BaseSource is not readable.");
			}
		}

		public virtual long Length
		{
			get
			{
				if (!CanSeek)
				{
					return 0L;
				}
				return BaseSource.Length;
			}
		}

		public bool CanSeek => BaseSource.CanSeek;

		public virtual ISampleSource BaseSource
		{
			get
			{
				return _baseSource;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				_baseSource = value;
			}
		}

		public bool DisposeBaseSource { get; set; }

		public SampleAggregatorBase(ISampleSource source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			_baseSource = source;
			DisposeBaseSource = true;
		}

		public virtual int Read(float[] buffer, int offset, int count)
		{
			if (offset % WaveFormat.Channels != 0)
			{
				offset -= offset % WaveFormat.Channels;
			}
			if (count % WaveFormat.Channels != 0)
			{
				count -= count % WaveFormat.Channels;
			}
			return BaseSource.Read(buffer, offset, count);
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				Dispose(disposing: true);
				GC.SuppressFinalize(this);
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			if (DisposeBaseSource && BaseSource != null)
			{
				BaseSource.Dispose();
				_baseSource = null;
			}
		}

		~SampleAggregatorBase()
		{
			Dispose(disposing: false);
		}
	}
	public static class Extensions
	{
		public static TimeSpan GetLength(this IAudioSource source)
		{
			return source.GetTime(source.Length);
		}

		public static TimeSpan GetPosition(this IAudioSource source)
		{
			return source.GetTime(source.Position);
		}

		public static void SetPosition(this IAudioSource source, TimeSpan position)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (position.TotalMilliseconds < 0.0)
			{
				throw new ArgumentOutOfRangeException("position");
			}
			long rawElements = source.GetRawElements(position);
			source.Position = rawElements;
		}

		public static TimeSpan GetTime(this IAudioSource source, long elementCount)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (elementCount < 0)
			{
				throw new ArgumentNullException("elementCount");
			}
			return TimeConverterFactory.Instance.GetTimeConverterForSource(source).ToTimeSpan(source.WaveFormat, elementCount);
		}

		public static long GetMilliseconds(this IAudioSource source, long elementCount)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (elementCount < 0)
			{
				throw new ArgumentOutOfRangeException("elementCount");
			}
			return (long)source.GetTime(elementCount).TotalMilliseconds;
		}

		public static long GetRawElements(this IAudioSource source, TimeSpan timespan)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return TimeConverterFactory.Instance.GetTimeConverterForSource(source).ToRawElements(source.WaveFormat, timespan);
		}

		public static long GetRawElements(this IAudioSource source, long milliseconds)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (milliseconds < 0)
			{
				throw new ArgumentOutOfRangeException("milliseconds");
			}
			return source.GetRawElements(TimeSpan.FromMilliseconds(milliseconds));
		}

		public static void WriteToFile(this IWaveSource source, string filename)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			using FileStream stream = File.OpenWrite(filename);
			source.WriteToWaveStream(stream);
		}

		public static void WriteToWaveStream(this IWaveSource source, Stream stream)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (!stream.CanWrite)
			{
				throw new ArgumentException("Stream is not writeable.", "stream");
			}
			using WaveWriter waveWriter = new WaveWriter(stream, source.WaveFormat);
			byte[] array = new byte[source.WaveFormat.BytesPerSecond];
			int count;
			while ((count = source.Read(array, 0, array.Length)) > 0)
			{
				waveWriter.Write(array, 0, count);
			}
		}

		public static void WriteToStream(this IWaveSource waveSource, Stream stream)
		{
			if (waveSource == null)
			{
				throw new ArgumentNullException("waveSource");
			}
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (!stream.CanWrite)
			{
				throw new ArgumentException("Stream is not writeable.", "stream");
			}
			byte[] array = new byte[waveSource.WaveFormat.BytesPerSecond];
			int count;
			while ((count = waveSource.Read(array, 0, array.Length)) > 0)
			{
				stream.Write(array, 0, count);
			}
		}

		public static T[] CheckBuffer<T>(this T[] inst, long size, bool exactSize = false)
		{
			if (inst == null || (!exactSize && inst.Length < size) || (exactSize && inst.Length != size))
			{
				return new T[size];
			}
			return inst;
		}

		internal static byte[] ReadBytes(this IWaveSource waveSource, int count)
		{
			if (waveSource == null)
			{
				throw new ArgumentNullException("waveSource");
			}
			count -= count % waveSource.WaveFormat.BlockAlign;
			if (count <= 0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			byte[] array = new byte[count];
			int num = waveSource.Read(array, 0, array.Length);
			if (num < count)
			{
				Array.Resize(ref array, num);
			}
			return array;
		}

		internal static bool IsClosed(this Stream stream)
		{
			if (!stream.CanRead)
			{
				return !stream.CanWrite;
			}
			return false;
		}

		internal static bool IsEndOfStream(this Stream stream)
		{
			return stream.Position == stream.Length;
		}

		internal static int LowWord(this int number)
		{
			return number & 0xFFFF;
		}

		internal static int LowWord(this int number, int newValue)
		{
			return (int)((number & 0xFFFF0000u) + (newValue & 0xFFFF));
		}

		internal static int HighWord(this int number)
		{
			return (int)(number & 0xFFFF0000u);
		}

		internal static int HighWord(this int number, int newValue)
		{
			return (number & 0xFFFF) + (newValue << 16);
		}

		internal static uint LowWord(this uint number)
		{
			return number & 0xFFFFu;
		}

		internal static uint LowWord(this uint number, int newValue)
		{
			return (uint)((uint)((int)number & -65536) + (newValue & 0xFFFF));
		}

		internal static uint HighWord(this uint number)
		{
			return number & 0xFFFF0000u;
		}

		internal static uint HighWord(this uint number, int newValue)
		{
			return (uint)((number & 0xFFFF) + (newValue << 16));
		}

		internal static Guid GetGuid(this object obj)
		{
			return obj.GetType().GUID;
		}

		internal static void WaitForExit(this Thread thread)
		{
			if (thread != null)
			{
				if (thread == Thread.CurrentThread)
				{
					throw new InvalidOperationException("Deadlock detected.");
				}
				thread.Join();
			}
		}

		internal static bool WaitForExit(this Thread thread, int timeout)
		{
			if (thread == null)
			{
				return true;
			}
			if (thread == Thread.CurrentThread)
			{
				throw new InvalidOperationException("Deadlock detected.");
			}
			return thread.Join(timeout);
		}

		internal static bool IsPCM(this WaveFormat waveFormat)
		{
			if (waveFormat == null)
			{
				throw new ArgumentNullException("waveFormat");
			}
			if (waveFormat is WaveFormatExtensible)
			{
				return ((WaveFormatExtensible)waveFormat).SubFormat == AudioSubTypes.Pcm;
			}
			return waveFormat.WaveFormatTag == AudioEncoding.Pcm;
		}

		internal static bool IsIeeeFloat(this WaveFormat waveFormat)
		{
			if (waveFormat == null)
			{
				throw new ArgumentNullException("waveFormat");
			}
			if (waveFormat is WaveFormatExtensible)
			{
				return ((WaveFormatExtensible)waveFormat).SubFormat == AudioSubTypes.IeeeFloat;
			}
			return waveFormat.WaveFormatTag == AudioEncoding.IeeeFloat;
		}

		internal static AudioEncoding GetWaveFormatTag(this WaveFormat waveFormat)
		{
			if (waveFormat is WaveFormatExtensible)
			{
				return AudioSubTypes.EncodingFromSubType(((WaveFormatExtensible)waveFormat).SubFormat);
			}
			return waveFormat.WaveFormatTag;
		}

		public static bool WaitForStopped(this ISoundOut soundOut, int millisecondsTimeout)
		{
			if (soundOut == null)
			{
				throw new ArgumentNullException("soundOut");
			}
			if (millisecondsTimeout < -1)
			{
				throw new ArgumentOutOfRangeException("millisecondsTimeout");
			}
			if (soundOut.PlaybackState == PlaybackState.Stopped)
			{
				return true;
			}
			AutoResetEvent waitHandle = new AutoResetEvent(initialState: false);
			try
			{
				EventHandler<PlaybackStoppedEventArgs> value = delegate
				{
					waitHandle.Set();
				};
				soundOut.Stopped += value;
				bool result = waitHandle.WaitOne(millisecondsTimeout);
				soundOut.Stopped -= value;
				return result;
			}
			finally
			{
				if (waitHandle != null)
				{
					((IDisposable)waitHandle).Dispose();
				}
			}
		}

		public static void WaitForStopped(this ISoundOut soundOut)
		{
			soundOut.WaitForStopped(-1);
		}

		internal static void SetValueForValueType<T>(this FieldInfo field, ref T item, object value) where T : struct
		{
			field.SetValueDirect(__makeref(item), value);
		}
	}
}
namespace CSCore.SoundOut
{
	public class PlaybackStoppedEventArgs : StoppedEventArgs
	{
		public PlaybackStoppedEventArgs()
			: this(null)
		{
		}

		public PlaybackStoppedEventArgs(Exception exception)
			: base(exception)
		{
		}
	}
}
namespace CSCore.Codecs.WAV
{
	public class WaveWriter : IDisposable, IWriteable
	{
		private readonly WaveFormat _waveFormat;

		private readonly long _waveStartPosition;

		private int _dataLength;

		private bool _isDisposed;

		private Stream _stream;

		private BinaryWriter _writer;

		private bool _isDisposing;

		private readonly bool _closeStream;

		public bool IsDisposed => _isDisposed;

		public bool IsDisposing => _isDisposing;

		public WaveWriter(string fileName, WaveFormat waveFormat)
			: this(File.OpenWrite(fileName), waveFormat)
		{
			_closeStream = true;
		}

		public WaveWriter(Stream stream, WaveFormat waveFormat)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (!stream.CanWrite)
			{
				throw new ArgumentException("Stream not writeable.", "stream");
			}
			if (!stream.CanSeek)
			{
				throw new ArgumentException("Stream not seekable.", "stream");
			}
			_isDisposing = false;
			_isDisposed = false;
			_stream = stream;
			_waveStartPosition = stream.Position;
			_writer = new BinaryWriter(stream);
			for (int i = 0; i < 44; i++)
			{
				_writer.Write((byte)0);
			}
			_waveFormat = waveFormat;
			WriteHeader();
			_closeStream = false;
		}

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

		[Obsolete("Use the Extensions.WriteToWaveStream extension instead.")]
		public static void WriteToFile(string filename, IWaveSource source, bool deleteFileIfAlreadyExists, int maxlength = -1)
		{
			if (deleteFileIfAlreadyExists && File.Exists(filename))
			{
				File.Delete(filename);
			}
			int num = 0;
			byte[] array = new byte[source.WaveFormat.BytesPerSecond];
			using WaveWriter waveWriter = new WaveWriter(filename, source.WaveFormat);
			int num2;
			while ((num2 = source.Read(array, 0, array.Length)) > 0)
			{
				waveWriter.Write(array, 0, num2);
				num += num2;
				if (maxlength != -1 && num > maxlength)
				{
					break;
				}
			}
		}

		public void WriteSample(float sample)
		{
			CheckObjectDisposed();
			if (sample < -1f || sample > 1f)
			{
				sample = Math.Max(-1f, Math.Min(1f, sample));
			}
			if (_waveFormat.IsPCM())
			{
				switch (_waveFormat.BitsPerSample)
				{
				case 8:
					Write((byte)(255f * sample));
					break;
				case 16:
					Write((short)(32767f * sample));
					break;
				case 24:
				{
					byte[] bytes = BitConverter.GetBytes((int)(8388607f * sample));
					Write(new byte[3]
					{
						bytes[0],
						bytes[1],
						bytes[2]
					}, 0, 3);
					break;
				}
				case 32:
					Write((int)(2.1474836E+09f * sample));
					break;
				default:
					throw new InvalidOperationException("Invalid Waveformat", new InvalidOperationException("Invalid BitsPerSample while using PCM encoding."));
				}
			}
			else if (_waveFormat.IsIeeeFloat())
			{
				Write(sample);
			}
			else
			{
				if (_waveFormat.WaveFormatTag != AudioEncoding.Extensible || _waveFormat.BitsPerSample != 32)
				{
					throw new InvalidOperationException("Invalid Waveformat: Waveformat has to be PCM[8, 16, 24, 32] or IeeeFloat[32]");
				}
				Write(65535 * (int)sample);
			}
		}

		public void WriteSamples(float[] samples, int offset, int count)
		{
			CheckObjectDisposed();
			for (int i = offset; i < offset + count; i++)
			{
				WriteSample(samples[i]);
			}
		}

		public void Write(byte[] buffer, int offset, int count)
		{
			CheckObjectDisposed();
			_stream.Write(buffer, offset, count);
			_dataLength += count;
		}

		public void Write(byte value)
		{
			CheckObjectDisposed();
			_writer.Write(value);
			_dataLength++;
		}

		public void Write(short value)
		{
			CheckObjectDisposed();
			_writer.Write(value);
			_dataLength += 2;
		}

		public void Write(int value)
		{
			CheckObjectDisposed();
			_writer.Write(value);
			_dataLength += 4;
		}

		public void Write(float value)
		{
			CheckObjectDisposed();
			_writer.Write(value);
			_dataLength += 4;
		}

		private void WriteHeader()
		{
			_writer.Flush();
			long position = _stream.Position;
			_stream.Position = _waveStartPosition;
			WriteRiffHeader();
			WriteFmtChunk();
			WriteDataChunk();
			_writer.Flush();
			_stream.Position = position;
		}

		private void WriteRiffHeader()
		{
			_writer.Write(Encoding.UTF8.GetBytes("RIFF"));
			_writer.Write((int)(_stream.Length - 8));
			_writer.Write(Encoding.UTF8.GetBytes("WAVE"));
		}

		private void WriteFmtChunk()
		{
			AudioEncoding audioEncoding = _waveFormat.WaveFormatTag;
			if (audioEncoding == AudioEncoding.Extensible && _waveFormat is WaveFormatExtensible)
			{
				audioEncoding = AudioSubTypes.EncodingFromSubType((_waveFormat as WaveFormatExtensible).SubFormat);
			}
			_writer.Write(Encoding.UTF8.GetBytes("fmt "));
			_writer.Write(16);
			_writer.Write((short)audioEncoding);
			_writer.Write((short)_waveFormat.Channels);
			_writer.Write(_waveFormat.SampleRate);
			_writer.Write(_waveFormat.BytesPerSecond);
			_writer.Write((short)_waveFormat.BlockAlign);
			_writer.Write((short)_waveFormat.BitsPerSample);
		}

		private void WriteDataChunk()
		{
			_writer.Write(Encoding.UTF8.GetBytes("data"));
			_writer.Write(_dataLength);
		}

		private void CheckObjectDisposed()
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("WaveWriter");
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_isDisposed || !disposing)
			{
				return;
			}
			try
			{
				_isDisposing = true;
				WriteHeader();
			}
			catch (Exception)
			{
			}
			finally
			{
				if (_closeStream)
				{
					if (_writer != null)
					{
						_writer.Close();
						_writer = null;
					}
					if (_stream != null)
					{
						_stream.Dispose();
						_stream = null;
					}
				}
				_isDisposing = false;
			}
			_isDisposed = true;
		}

		~WaveWriter()
		{
			Dispose(disposing: false);
		}
	}
}
namespace CSCore.SoundOut
{
	public interface ISoundOut : IDisposable
	{
		float Volume { get; set; }

		IWaveSource WaveSource { get; }

		PlaybackState PlaybackState { get; }

		event EventHandler<PlaybackStoppedEventArgs> Stopped;

		void Play();

		void Pause();

		void Resume();

		void Stop();

		void Initialize(IWaveSource source);
	}
	public enum PlaybackState
	{
		Stopped,
		Playing,
		Paused
	}
}
namespace CSCore
{
	public abstract class WaveAggregatorBase : IWaveAggregator, IWaveSource, IReadableAudioSource<byte>, IAudioSource, IDisposable, IAggregator<byte, IWaveSource>
	{
		private IWaveSource _baseSource;

		private bool _disposed;

		public bool DisposeBaseSource { get; set; }

		public virtual IWaveSource BaseSource
		{
			get
			{
				return _baseSource;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "BaseSource must not be null.");
				}
				_baseSource = value;
			}
		}

		public virtual WaveFormat WaveFormat => BaseSource.WaveFormat;

		public virtual long Position
		{
			get
			{
				if (!CanSeek)
				{
					return 0L;
				}
				return BaseSource.Position;
			}
			set
			{
				if (CanSeek)
				{
					value -= value % WaveFormat.BlockAlign;
					BaseSource.Position = value;
					return;
				}
				throw new InvalidOperationException();
			}
		}

		public virtual long Length
		{
			get
			{
				if (!CanSeek)
				{
					return 0L;
				}
				return BaseSource.Length;
			}
		}

		public virtual bool CanSeek => BaseSource.CanSeek;

		protected WaveAggregat