diff --git a/.gitignore b/.gitignore index ccc307f..0ba4271 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,7 @@ TestResult.xml nunit-*.xml publish -publish.sh \ No newline at end of file +publish.sh + +# Desktop specific +.DS_Store diff --git a/GraphAudio.Kit/GraphAudio.Kit.csproj b/GraphAudio.Kit/GraphAudio.Kit.csproj index c4085f1..bf64d38 100644 --- a/GraphAudio.Kit/GraphAudio.Kit.csproj +++ b/GraphAudio.Kit/GraphAudio.Kit.csproj @@ -32,7 +32,7 @@ - + diff --git a/GraphAudio.SteamAudio/GraphAudio.SteamAudio.csproj b/GraphAudio.SteamAudio/GraphAudio.SteamAudio.csproj index 46c80a9..d9f2c46 100644 --- a/GraphAudio.SteamAudio/GraphAudio.SteamAudio.csproj +++ b/GraphAudio.SteamAudio/GraphAudio.SteamAudio.csproj @@ -12,7 +12,7 @@ the-byte-bender Spatial audio for GraphAudio using Steam Audio 2025 - 0.4.2 + 0.4.3 GraphAudio.SteamAudio https://github.com/the-byte-bender/GraphAudio https://github.com/the-byte-bender/GraphAudio diff --git a/GraphAudio.SteamAudio/SteamAudioContext.cs b/GraphAudio.SteamAudio/SteamAudioContext.cs index 53ed808..9af9e61 100644 --- a/GraphAudio.SteamAudio/SteamAudioContext.cs +++ b/GraphAudio.SteamAudio/SteamAudioContext.cs @@ -63,6 +63,7 @@ private static SteamAudioResources GetOrCreate(AudioContextBase context) { return _contextMap.GetOrAdd(context, ctx => { + SteamAudioNativeLoader.EnsureLoaded(); var resources = new SteamAudioResources(ctx.SampleRate, AudioBuffer.FramesPerBlock); var contextSettings = new IPL.ContextSettings diff --git a/GraphAudio.SteamAudio/SteamAudioNativeLoader.cs b/GraphAudio.SteamAudio/SteamAudioNativeLoader.cs new file mode 100644 index 0000000..00b1757 --- /dev/null +++ b/GraphAudio.SteamAudio/SteamAudioNativeLoader.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace GraphAudio.SteamAudio; + +/// +/// Handles native library loading for SteamAudio on macOS where the NuGet package +/// uses osx-universal RID instead of osx-arm64/osx-x64. +/// +internal static class SteamAudioNativeLoader +{ + private static bool _isRegistered = false; + private static readonly object _lock = new object(); + + /// + /// Registers the DllImport resolver for SteamAudio native libraries. + /// + internal static void EnsureLoaded() + { + lock (_lock) + { + if (_isRegistered) return; + + var steamAudioAssembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "SteamAudio.NET"); + + if (steamAudioAssembly != null) + { + NativeLibrary.SetDllImportResolver(steamAudioAssembly, DllImportResolver); + } + + _isRegistered = true; + } + } + + private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + { + if (!libraryName.Equals("phonon.dll", StringComparison.OrdinalIgnoreCase) && + !libraryName.Equals("phonon", StringComparison.OrdinalIgnoreCase)) + { + return IntPtr.Zero; + } + + // Try base directory first (for .app bundles where dylibs are in MacOS/) + var baseDirectoryPath = GetBaseDirectoryPath(); + if (baseDirectoryPath != null && File.Exists(baseDirectoryPath)) + { + if (NativeLibrary.TryLoad(baseDirectoryPath, out var handle)) + return handle; + } + + var archSpecificPath = GetArchitectureSpecificPath(); + if (archSpecificPath != null && File.Exists(archSpecificPath)) + { + if (NativeLibrary.TryLoad(archSpecificPath, out var handle)) + return handle; + } + + var universalPath = GetUniversalPath(); + if (universalPath != null && File.Exists(universalPath)) + { + if (NativeLibrary.TryLoad(universalPath, out var handle)) + return handle; + } + + return IntPtr.Zero; + } + + private static string? GetBaseDirectoryPath() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return null; + + return Path.Combine(AppContext.BaseDirectory, "libphonon.dylib"); + } + + private static string? GetArchitectureSpecificPath() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return null; + + var baseDir = AppContext.BaseDirectory; + var arch = RuntimeInformation.ProcessArchitecture; + var rid = arch == Architecture.Arm64 ? "osx-arm64" : "osx-x64"; + + return Path.Combine(baseDir, "runtimes", rid, "native", "libphonon.dylib"); + } + + private static string? GetUniversalPath() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return null; + + return Path.Combine(AppContext.BaseDirectory, "runtimes", "osx-universal", "native", "libphonon.dylib"); + } +} diff --git a/pack-local.sh b/pack-local.sh old mode 100644 new mode 100755