Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VoiceMusicBoost v1.0.1
VoiceMusicBoost-1.0.1.dll
Decompiled 2 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Photon.Voice; using Photon.Voice.Unity; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace VoiceMusicBoost; [BepInPlugin("com.voicemusicboost.repo", "音乐语音增强 (VoiceMusicBoost)", "1.0.1")] public sealed class VoiceMusicBoostPlugin : BaseUnityPlugin { public const string Guid = "com.voicemusicboost.repo"; public const string Version = "1.0.1"; internal static ManualLogSource L; internal static ConfigEntry<bool> CfgEnable; internal static ConfigEntry<int> CfgBitrate; internal static ConfigEntry<int> CfgSampling; internal static ConfigEntry<int> CfgFrameMs; internal static ConfigEntry<bool> CfgDisableVad; internal static ConfigEntry<float> CfgVadThreshold; internal static ConfigEntry<bool> CfgBypassDsp; internal static ConfigEntry<bool> CfgReliable; internal static ConfigEntry<bool> CfgVerbose; private Harmony _harmony; private void Awake() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown L = ((BaseUnityPlugin)this).Logger; CfgEnable = ((BaseUnityPlugin)this).Config.Bind<bool>("1-编码参数", "启用编码覆盖", true, "是否在每次开启录音时覆盖 Opus 编码参数。\n关闭后本插件的编码覆盖失效,仅保留 VAD 与 WebRTC 音效链的处理开关。"); CfgBitrate = ((BaseUnityPlugin)this).Config.Bind<int>("1-编码参数", "Opus 码率 (bps)", 96000, new ConfigDescription("6000 ~ 510000。游戏默认 30000(约 30kbps,人声级别),音乐必然发闷断续。\n建议值:64000(够用) / 96000(推荐) / 128000(音质最好,占用上行带宽最高)。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6000, 510000), Array.Empty<object>())); CfgSampling = ((BaseUnityPlugin)this).Config.Bind<int>("1-编码参数", "采样率 (Hz)", 48000, new ConfigDescription("16000 / 24000 / 32000 / 48000。游戏默认 24000,音乐高频会被削掉。\n48000 为音乐首选;若上行带宽紧张可退到 32000。", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 16000, 24000, 32000, 48000 }), Array.Empty<object>())); CfgFrameMs = ((BaseUnityPlugin)this).Config.Bind<int>("1-编码参数", "帧长 (毫秒)", 40, new ConfigDescription("20 / 40 / 60。游戏默认 20。\n40 在抗抖动与延迟之间较均衡,音乐推荐;20 延迟最低但更容易被丢包撕碎。", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[3] { 20, 40, 60 }), Array.Empty<object>())); CfgDisableVad = ((BaseUnityPlugin)this).Config.Bind<bool>("2-音频处理", "关闭语音检测 (VAD)", true, "游戏的语音检测会把安静段落和低频段落判定为\"没说话\"从而停止发送,音乐会出现频繁断口。\n强烈建议保持开启(关闭 VAD)。"); CfgVadThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("2-音频处理", "语音检测阈值", 0.001f, new ConfigDescription("仅在未能关闭 VAD 时生效,越低越不容易被切断。范围 0.0001 ~ 0.1。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.0001f, 0.1f), Array.Empty<object>())); CfgBypassDsp = ((BaseUnityPlugin)this).Config.Bind<bool>("2-音频处理", "关闭 WebRTC 音效处理", true, "关闭回声消除(AEC) / 噪声抑制(NS) / 自动增益(AGC) / 高通滤波 / WebRTC 自带语音检测。\n这些算法是按人声设计的,会把音乐当成噪声压制,是断续与发闷的主要来源之一。\n副作用:若你外放音箱而非戴耳机,队友可能听到回声。"); CfgReliable = ((BaseUnityPlugin)this).Config.Bind<bool>("3-传输", "可靠传输", false, "开启后丢包会重传,音乐不易被丢包撕裂,但会增加延迟与带宽占用。\n网络稳定时建议关闭;队友那边持续爆音/断续时可尝试开启。"); CfgVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("4-诊断", "输出详细日志", true, "在日志中打印每次生效的编码参数与实际麦克风采样率,便于确认是否真的生效。"); _harmony = new Harmony("com.voicemusicboost.repo"); TryPatch(typeof(Patch_RecorderCreateVoice), "编码参数"); TryPatch(typeof(Patch_WebRtcAwake), "WebRTC 音效链"); TryPatch(typeof(Patch_VoiceCreatedDiagnostics), "诊断日志"); L.LogInfo((object)("音乐语音增强已加载:码率 " + CfgBitrate.Value + "bps / 采样率 " + CfgSampling.Value + "Hz / 帧长 " + CfgFrameMs.Value + "ms / 关闭VAD=" + CfgDisableVad.Value + " / 关闭WebRTC处理=" + CfgBypassDsp.Value + "(装在本机即生效,房主/客机身份相同)")); } private void TryPatch(Type patchType, string label) { try { _harmony.PatchAll(patchType); } catch (Exception ex) { L.LogError((object)("[" + label + "] 补丁失败:" + ex.Message)); } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } internal static void LogI(string msg) { if (L != null) { L.LogInfo((object)msg); } } internal static void LogV(string msg) { if (L != null && CfgVerbose != null && CfgVerbose.Value) { L.LogInfo((object)msg); } } } [HarmonyPatch(typeof(Recorder), "CreateLocalVoiceAudioAndSource")] internal static class Patch_RecorderCreateVoice { private static readonly FieldInfo FBitrate = AccessTools.Field(typeof(Recorder), "bitrate"); private static readonly FieldInfo FSampling = AccessTools.Field(typeof(Recorder), "samplingRate"); private static readonly FieldInfo FFrame = AccessTools.Field(typeof(Recorder), "frameDuration"); private static readonly FieldInfo FVoiceDetection = AccessTools.Field(typeof(Recorder), "voiceDetection"); private static readonly FieldInfo FThreshold = AccessTools.Field(typeof(Recorder), "voiceDetectionThreshold"); private static readonly FieldInfo FReliable = AccessTools.Field(typeof(Recorder), "reliableMode"); private static void Prefix(Recorder __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } if (VoiceMusicBoostPlugin.CfgEnable.Value) { int num = Mathf.Clamp(VoiceMusicBoostPlugin.CfgBitrate.Value, 6000, 510000); FBitrate?.SetValue(__instance, num); int value = VoiceMusicBoostPlugin.CfgSampling.Value; if (FSampling != null && Enum.IsDefined(FSampling.FieldType, value)) { FSampling.SetValue(__instance, Enum.ToObject(FSampling.FieldType, value)); } else { VoiceMusicBoostPlugin.LogI("[编码] 采样率 " + value + "Hz 不被 Opus 封装枚举支持,保持游戏默认值。"); } int value2 = VoiceMusicBoostPlugin.CfgFrameMs.Value; if (FFrame != null && Enum.IsDefined(FFrame.FieldType, value2 * 1000)) { FFrame.SetValue(__instance, Enum.ToObject(FFrame.FieldType, value2 * 1000)); } else { VoiceMusicBoostPlugin.LogI("[编码] 帧长 " + value2 + "ms 不被 Opus 封装枚举支持,保持游戏默认值。"); } } if (VoiceMusicBoostPlugin.CfgDisableVad.Value) { FVoiceDetection?.SetValue(__instance, false); } else { FThreshold?.SetValue(__instance, VoiceMusicBoostPlugin.CfgVadThreshold.Value); } FReliable?.SetValue(__instance, VoiceMusicBoostPlugin.CfgReliable.Value); VoiceMusicBoostPlugin.LogV("[编码] 已应用:bitrate=" + (FBitrate?.GetValue(__instance))?.ToString() + " sampling=" + (FSampling?.GetValue(__instance))?.ToString() + " frame=" + (FFrame?.GetValue(__instance))?.ToString() + " voiceDetection=" + (FVoiceDetection?.GetValue(__instance))?.ToString() + " reliable=" + FReliable?.GetValue(__instance)); } catch (Exception ex) { VoiceMusicBoostPlugin.LogI("[编码] 应用参数异常:" + ex.Message); } } } [HarmonyPatch(typeof(WebRtcAudioDsp), "Awake")] internal static class Patch_WebRtcAwake { private static void Postfix(WebRtcAudioDsp __instance) { try { if (!((Object)(object)__instance == (Object)null) && VoiceMusicBoostPlugin.CfgBypassDsp.Value) { __instance.AEC = false; __instance.AecHighPass = false; __instance.NoiseSuppression = false; __instance.HighPass = false; __instance.AGC = false; __instance.VAD = false; __instance.Bypass = true; VoiceMusicBoostPlugin.LogI("[音效] 已关闭 AEC / 噪声抑制 / AGC / 高通滤波 / WebRTC VAD,并旁路处理链。"); } } catch (Exception ex) { VoiceMusicBoostPlugin.LogI("[音效] 关闭处理链失败:" + ex.Message); } } } [HarmonyPatch] internal static class Patch_VoiceCreatedDiagnostics { private static FieldInfo _fRecorder; private static FieldInfo _fMicSource; private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("PlayerVoiceChat"); if (!(type == null)) { return AccessTools.Method(type, "PhotonVoiceCreated", (Type[])null, (Type[])null); } return null; } private static void Postfix(object __instance, PhotonVoiceCreatedParams p) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) try { if (p == null || !VoiceMusicBoostPlugin.CfgVerbose.Value) { return; } VoiceInfo val = (VoiceInfo)((p.Voice != null) ? p.Voice.Info : default(VoiceInfo)); string text = ((p.Voice == null) ? "?" : ((object)p.Voice).GetType().Name); string text2 = "[实际语音流] 采样率=" + ((VoiceInfo)(ref val)).SamplingRate + "Hz 声道=" + ((VoiceInfo)(ref val)).Channels + " 帧长=" + (float)((VoiceInfo)(ref val)).FrameDurationUs / 1000f + "ms 码率=" + ((VoiceInfo)(ref val)).Bitrate + "bps 采样管道=" + text; if (__instance != null) { if (_fRecorder == null) { _fRecorder = AccessTools.Field(__instance.GetType(), "recorder"); } object? obj = _fRecorder?.GetValue(__instance); Recorder val2 = (Recorder)((obj is Recorder) ? obj : null); if ((Object)(object)val2 != (Object)null) { text2 = text2 + " | Recorder: " + ((object)val2.SamplingRate/*cast due to .constrained prefix*/).ToString() + " / " + ((object)val2.FrameDuration/*cast due to .constrained prefix*/).ToString() + " / " + val2.Bitrate + "bps / VAD=" + val2.VoiceDetection + " / Reliable=" + val2.ReliableMode; } if (_fMicSource == null) { _fMicSource = AccessTools.Field(__instance.GetType(), "microphoneSource"); } object? obj2 = _fMicSource?.GetValue(__instance); IAudioDesc val3 = (IAudioDesc)((obj2 is IAudioDesc) ? obj2 : null); if (val3 != null) { text2 = text2 + " | 麦克风输入: " + val3.SamplingRate + "Hz x" + val3.Channels; if (val3.SamplingRate < 32000) { text2 += " ← 偏低!系统或设备把输入压到了电话级别,请检查声卡/虚拟声卡的格式与\"通信设备\"设置。"; } } } VoiceMusicBoostPlugin.LogI(text2); } catch (Exception ex) { VoiceMusicBoostPlugin.LogI("[诊断] 读取语音流参数失败:" + ex.Message); } } }