From 04a650f8ece2ba489a05d0e112fa5ebd7ecebd06 Mon Sep 17 00:00:00 2001 From: Arne Kiesewetter Date: Sat, 21 Mar 2026 16:09:57 +0100 Subject: [PATCH] Handle Streaming output the same the default output in AudioSystem update Adds a fix for https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/6211 --- .../CommunityBugFixCollection.csproj | 1 + .../LinuxStreamingAudioFix.cs | 97 +++++++++++++++++++ CommunityBugFixCollection/Locale/de.json | 4 + CommunityBugFixCollection/Locale/en.json | 4 + README.md | 1 + 5 files changed, 107 insertions(+) create mode 100644 CommunityBugFixCollection/LinuxStreamingAudioFix.cs diff --git a/CommunityBugFixCollection/CommunityBugFixCollection.csproj b/CommunityBugFixCollection/CommunityBugFixCollection.csproj index 4194b95..7558a59 100644 --- a/CommunityBugFixCollection/CommunityBugFixCollection.csproj +++ b/CommunityBugFixCollection/CommunityBugFixCollection.csproj @@ -24,6 +24,7 @@ + diff --git a/CommunityBugFixCollection/LinuxStreamingAudioFix.cs b/CommunityBugFixCollection/LinuxStreamingAudioFix.cs new file mode 100644 index 0000000..c2a3752 --- /dev/null +++ b/CommunityBugFixCollection/LinuxStreamingAudioFix.cs @@ -0,0 +1,97 @@ +using Elements.Core; +using FrooxEngine; +using HarmonyLib; +using MonkeyLoader; +using MonkeyLoader.Meta; + +namespace CommunityBugFixCollection +{ + [HarmonyPatch] + [HarmonyPatchCategory(nameof(LinuxStreamingAudioFix))] + internal sealed class LinuxStreamingAudioFix : ResoniteBugFixMonkey + { + private static readonly Version _requiredShowmanToolsVersion = new(0, 2, 0); + public override IEnumerable Authors => Contributors.Banane9; + + protected override bool OnEngineReady() + { + if (Mod.Loader.TryGet().ById("ShowmanTools", out var mod) && mod.Version.Version >= _requiredShowmanToolsVersion) + { + Logger.Info(() => "Skipping in favor of the ShowmanTools fix."); + return false; + } + + return base.OnEngineReady(); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(AudioSystem), nameof(AudioSystem.UpdateDefaultAudioOutput))] + private static bool UpdateDefaultAudioOutputPrefix(AudioSystem __instance, Action? ___DefaultAudioOutputChanged) + { + if (__instance._outputDevice is null) + return false; + + var preferredDevice = __instance._outputDevice.FindPreferredDevice(d => __instance._audioOutputDeviceIDs.Contains(d.EntryID)); + var preferredStreamingDevice = __instance._outputDevice.FindStreamingPreferredDevice(d => __instance._audioOutputDeviceIDs.Contains(d.EntryID)); + + var preferredDeviceID = preferredDevice is not null + ? (string)preferredDevice.EntryID + : (__instance.AudioOutputs.FirstOrDefault(o => o.IsSystemDefault && o.IsConnected)?.DeviceID); + + if (preferredDeviceID is null) + { + UniLog.Warning("Cannot find a preferred device ID"); + return false; + } + + var preferredStreamingDeviceID = preferredStreamingDevice?.EntryID.Value; + + if (preferredDeviceID == __instance.DefaultAudioOutput?.DeviceID && preferredStreamingDeviceID == __instance.StreamingAudioOutput?.DeviceID) + return false; + + __instance.PrimaryOutput.Device = null; + __instance.StreamingOutput.Device = null; + + var oldDefault = __instance.DefaultAudioOutput; + var oldStreaming = __instance.StreamingAudioOutput; + + if (oldDefault is not null) + { + oldDefault.Stop(); + oldDefault.RenderAudio = null; + } + + if (oldStreaming is not null) + { + oldStreaming.Stop(); + oldStreaming.RenderAudio = null; + } + + __instance._defaultAudioOutputIndex = __instance.AudioOutputs.FindIndex(i => i.DeviceID == preferredDeviceID); + __instance._streamingAudioOutputIndex = __instance.AudioOutputs.FindIndex(i => i.DeviceID == preferredStreamingDeviceID); + + if (__instance._streamingAudioOutputIndex >= 0 && __instance._streamingAudioOutputIndex == __instance._defaultAudioOutputIndex) + __instance._streamingAudioOutputIndex = -1; + + var newDefault = __instance.DefaultAudioOutput!; + var newStreaming = __instance.StreamingAudioOutput; + + __instance.audioThreadLoop.Supress = true; + + newDefault.RenderAudio = __instance.RenderAudio; + newDefault.Start("Default Output"); + + if (newStreaming is not null) + { + newStreaming.RenderAudio = __instance.RenderAudio; + newStreaming.Start("Streaming Camera"); + } + + __instance.PrimaryOutput.Device = newDefault; + __instance.StreamingOutput.Device = newStreaming; + + ___DefaultAudioOutputChanged?.Invoke(newDefault); + return false; + } + } +} \ No newline at end of file diff --git a/CommunityBugFixCollection/Locale/de.json b/CommunityBugFixCollection/Locale/de.json index 5b5bca2..b9c43f5 100644 --- a/CommunityBugFixCollection/Locale/de.json +++ b/CommunityBugFixCollection/Locale/de.json @@ -30,6 +30,10 @@ "CommunityBugFixCollection.HighlightHomeWorldInInventory.Description": "Sorgt dafür, dass die ausgewählte Heimatwelt im Inventar korrekt hervorgehoben wird.", "CommunityBugFixCollection.ImportMultipleAudioFiles.Description": "Macht es möglich mehrere Audiodateien auf einmal zu importieren.", "CommunityBugFixCollection.ImportWebFilesAsUrls.Description": "Sorgt dafür, dass URLs zu Textdateien oder Resonite Packages nicht importiert werden, statt als Hyperlink aufzutauchen.", + + "ShowmanTools.LinuxStreamingAudioFix.Name": "Linux Streaming Audio Fix", + "ShowmanTools.LinuxStreamingAudioFix.Description": "Stellt sicher, dass das separate Audio-Output der Streamingkamera auf Linux funktioniert.", + "CommunityBugFixCollection.LocalizedByteFormatting.Description": "Lokalisiert die Speichereinheiten (MiB, GiB, etc.), inbsesondere bei der StorageUsageStatus-Komponente. Es gibt eine Einstellung dafür, die Bytes nach IEC (Faktor 1024) statt dezimal (Faktor 1000) zu formatieren.", "CommunityBugFixCollection.LongerWorldLoadingFailIndication.Description": "Lässt den Welt-Ladefortschritts-Indikator frühestens nach 20s verschwinden, falls der Vorgang fehlgeschlagen ist.", "CommunityBugFixCollection.NaNtEqual.Description": "Sorgt dafür, dass NaN float / double Werte sich bei den == und != ProtoFlux Nodes sowie bei der ValueEqualityDriver-Komponente niemals gleichen.", diff --git a/CommunityBugFixCollection/Locale/en.json b/CommunityBugFixCollection/Locale/en.json index 8f7f3f6..12b6865 100644 --- a/CommunityBugFixCollection/Locale/en.json +++ b/CommunityBugFixCollection/Locale/en.json @@ -36,6 +36,10 @@ "CommunityBugFixCollection.HighlightHomeWorldInInventory.Description": "Fixes the selected Home World in the Inventory not being highlighted as a favorite.", "CommunityBugFixCollection.ImportMultipleAudioFiles.Description": "Fixes it not being possible to import multiple audio clips at once.", "CommunityBugFixCollection.ImportWebFilesAsUrls.Description": "Fixes URLs to text files or Resonite Packages failing to import instead of appearing as a hyperlink.", + + "ShowmanTools.LinuxStreamingAudioFix.Name": "Linux Streaming Audio Fix", + "ShowmanTools.LinuxStreamingAudioFix.Description": "Ensures that the streaming camera's separate audio output works on Linux.", + "CommunityBugFixCollection.LocalizedByteFormatting.Description": "Localizes the storage units (MiB, GiB, etc.), in particular for the StorageUsageStatus component. There's an option to use IEC format (factor 1024) over decimal (factor 1000).", "CommunityBugFixCollection.LongerWorldLoadingFailIndication.Description": "Only lets the World Load Progress Indicator disappear after 20s or more if the process failed.", "CommunityBugFixCollection.NaNtEqual.Description": "Makes NaN floats / doubles never equal to each other for the ProtoFlux == and != nodes, as well as the ValueEqualityDriver component.", diff --git a/README.md b/README.md index 27306d8..ca72444 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ just disable them in the settings in the meantime. * DuplicateSlot ProtoFlux node crashes game when if OverrideParent is identical to Template (https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/3950) * April Fools content is active for users in Universes (commercial usage) (https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/4016) * Instantly removing an AudioOutput component crashes the session (https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/4286) +* Separate audio output for streaming camera doesn't work on Linux (https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/6211) Fixes with no issue (that could be found). * Content of notification being off-center.