using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("AudioOutput")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("\r\n Change audio output devices live in-game.\r\n ")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AudioOutput")] [assembly: AssemblyTitle("AudioOutput")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MoreAudioSettings { [BepInPlugin("cryingrgb.AudioOutput", "Audio Output", "1.0.1")] public class Plugin : BaseUnityPlugin { public static ConfigEntry OutputDeviceConfig; private static readonly Dictionary DeviceMap = new Dictionary(); private string currentDevice = string.Empty; private const string DefaultDevice = "Default System Device"; private bool audioCmdletsInstalled; private void Awake() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown audioCmdletsInstalled = IsAudioDeviceCmdletsInstalled(); if (!audioCmdletsInstalled) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Audio switching will be disabled."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Scanning Windows playback devices..."); List windowsPlaybackDevices = GetWindowsPlaybackDevices(); windowsPlaybackDevices.Insert(0, "Default System Device"); DeviceMap["Default System Device"] = "__DEFAULT__"; if (windowsPlaybackDevices.Count == 1) { windowsPlaybackDevices.Add("No Devices Found"); } string text = windowsPlaybackDevices[0]; OutputDeviceConfig = ((BaseUnityPlugin)this).Config.Bind("Audio", "Output Device", text, new ConfigDescription(audioCmdletsInstalled ? "Select the audio output device." : "AudioDeviceCmdlets missing. Run: Install-Module AudioDeviceCmdlets -Scope CurrentUser", (AcceptableValueBase)(object)new AcceptableValueList(windowsPlaybackDevices.ToArray()), Array.Empty())); currentDevice = OutputDeviceConfig.Value; OutputDeviceConfig.SettingChanged += delegate { if (!audioCmdletsInstalled) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot switch audio device: AudioDeviceCmdlets is not installed."); } else { ApplyDeviceRouting(OutputDeviceConfig.Value); } }; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded with {windowsPlaybackDevices.Count - 1} playback devices."); } private void ApplyDeviceRouting(string friendlyName) { if (currentDevice == friendlyName) { return; } currentDevice = friendlyName; if (friendlyName == "Default System Device") { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Using Windows default audio device."); return; } if (!DeviceMap.TryGetValue(friendlyName, out string value)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Invalid device: " + friendlyName)); return; } try { string text = "Import-Module AudioDeviceCmdlets; Set-AudioDevice -ID '" + value + "'"; using Process process = new Process(); process.StartInfo.FileName = "powershell.exe"; process.StartInfo.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"" + text + "\""; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); process.StandardOutput.ReadToEnd(); string text2 = process.StandardError.ReadToEnd(); process.WaitForExit(); if (process.ExitCode == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Switched audio device to: " + friendlyName)); } else { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed switching to '" + friendlyName + "'\n" + text2)); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Device switch failed:\n{arg}"); } } private List GetWindowsPlaybackDevices() { List list = new List(); DeviceMap.Clear(); try { using Process process = new Process(); process.StartInfo.FileName = "powershell.exe"; process.StartInfo.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"Get-AudioDevice -List | Where-Object {$_.Type -eq 'Playback'} | Select-Object Name,ID\""; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); string text = process.StandardOutput.ReadToEnd(); string text2 = process.StandardError.ReadToEnd(); process.WaitForExit(); if (!string.IsNullOrWhiteSpace(text2)) { ((BaseUnityPlugin)this).Logger.LogError((object)("PowerShell Error:\n" + text2)); return list; } string[] array = text.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text3 = array[i].Trim(); if (text3.StartsWith("Name") || text3.StartsWith("---")) { continue; } int num = text3.IndexOf("{0.0.0."); if (num >= 0) { string text4 = text3.Substring(0, num).Trim(); string value = text3.Substring(num).Trim(); if (!string.IsNullOrWhiteSpace(text4) && !string.IsNullOrWhiteSpace(value) && !DeviceMap.ContainsKey(text4)) { DeviceMap[text4] = value; list.Add(text4); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Detected device: " + text4)); } } } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to enumerate devices:\n{arg}"); } return list; } private bool IsAudioDeviceCmdletsInstalled() { try { using Process process = Process.Start(new ProcessStartInfo { FileName = "powershell.exe", Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"Get-Module -ListAvailable AudioDeviceCmdlets\"", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }); string value = process.StandardOutput.ReadToEnd(); process.StandardError.ReadToEnd(); process.WaitForExit(); if (string.IsNullOrWhiteSpace(value)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"AudioDeviceCmdlets is NOT installed!"); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Audio Output requires AudioDeviceCmdlets to switch devices."); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Run this command in PowerShell:"); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Install-Module AudioDeviceCmdlets -Scope CurrentUser"); return false; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"AudioDeviceCmdlets detected."); return true; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to check AudioDeviceCmdlets: {arg}"); return false; } } } }