diff --git a/src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs deleted file mode 100644 index 55a4a60e1..000000000 --- a/src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.Audio.Backends.SDL3 -{ - class SDL3AudioBuffer - { - public readonly ulong DriverIdentifier; - public readonly ulong SampleCount; - public ulong SamplePlayed; - - public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount) - { - DriverIdentifier = driverIdentifier; - SampleCount = sampleCount; - SamplePlayed = 0; - } - } -} diff --git a/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs index c3fd9e1db..831732ce2 100644 --- a/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs @@ -29,7 +29,7 @@ namespace Ryujinx.Audio.Backends.SDL3 SDL3Driver.Instance.Initialize(); - if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, out var spec, out int sample_frames)) + if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, out var spec, out int _)) { Logger.Error?.Print(LogClass.Application, $"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\""); @@ -48,8 +48,7 @@ namespace Ryujinx.Audio.Backends.SDL3 private static bool IsSupportedInternal() { - var device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, - Constants.TargetSampleCount, null); + var device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax); if (device != 0) { @@ -100,7 +99,7 @@ namespace Ryujinx.Audio.Backends.SDL3 } private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, - uint requestedChannelCount, uint sampleCount) + uint requestedChannelCount) { return new SDL_AudioSpec { @@ -123,10 +122,9 @@ namespace Ryujinx.Audio.Backends.SDL3 } internal static nint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, - uint requestedChannelCount, uint sampleCount, SDL_AudioStreamCallback callback) + uint requestedChannelCount) { - SDL_AudioSpec spec = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount, - sampleCount); + SDL_AudioSpec spec = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount); var stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, ref spec,null,IntPtr.Zero); diff --git a/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs index 62670cd0c..1151ac473 100644 --- a/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs +++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs @@ -1,12 +1,8 @@ using Ryujinx.Audio.Backends.Common; using Ryujinx.Audio.Common; using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; using Ryujinx.Memory; using System; -using System.Buffers; -using System.Collections.Concurrent; -using System.Runtime.InteropServices; using System.Threading; using static SDL3.SDL; @@ -15,14 +11,10 @@ namespace Ryujinx.Audio.Backends.SDL3 class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase { private readonly SDL3HardwareDeviceDriver _driver; - private readonly ConcurrentQueue _queuedBuffers; - private readonly DynamicRingBuffer _ringBuffer; private ulong _playedSampleCount; private readonly ManualResetEvent _updateRequiredEvent; private nint _outputStream; private bool _hasSetupError; - private readonly SDL_AudioStreamCallback _callbackDelegate; - private readonly int _bytesPerFrame; private uint _sampleCount; private bool _started; private float _volume; @@ -34,10 +26,6 @@ namespace Ryujinx.Audio.Backends.SDL3 { _driver = driver; _updateRequiredEvent = _driver.GetUpdateRequiredEvent(); - _queuedBuffers = new ConcurrentQueue(); - _ringBuffer = new DynamicRingBuffer(); - _callbackDelegate = Update; - _bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount; _nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat); _sampleCount = uint.MaxValue; _started = false; @@ -56,7 +44,7 @@ namespace Ryujinx.Audio.Backends.SDL3 _sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount); var newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, - RequestedChannelCount, _sampleCount, _callbackDelegate); + RequestedChannelCount); _hasSetupError = newOutputStream == 0; @@ -75,78 +63,6 @@ namespace Ryujinx.Audio.Backends.SDL3 } } - private unsafe void Update(nint userdata, IntPtr stream, int streamLength, int total_amount) - { - Console.WriteLine("call"); - Console.WriteLine(SDL_GetAudioDeviceName(SDL_GetAudioStreamDevice(stream))); - Span streamSpan = new((void*)stream, streamLength); - - int maxFrameCount = (int)GetSampleCount(streamLength); - int bufferedFrames = _ringBuffer.Length / _bytesPerFrame; - - int frameCount = Math.Min(bufferedFrames, maxFrameCount); - - if (frameCount == 0) - { - // SDL3 left the responsibility to the user to clear the buffer. - streamSpan.Clear(); - - return; - } - - using SpanOwner samplesOwner = SpanOwner.Rent(frameCount * _bytesPerFrame); - - Span samples = samplesOwner.Span; - - _ringBuffer.Read(samples, 0, samples.Length); - - // fixed (byte* p = samples) - // { - // nint pStreamSrc = (nint)p; - // - // // Zero the dest buffer - // streamSpan.Clear(); - // - // // Apply volume to written data - // // SDL_MixAudio(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume * _volume); - // IntPtr unmanagedBuffer = Marshal.AllocHGlobal(samples.Length); - // Marshal.Copy(p, 0, unmanagedBuffer, samples.Length); - // SDL_PutAudioStreamData(_outputStream, unmanagedBuffer,samples.Length); - // } - - - ulong sampleCount = GetSampleCount(samples.Length); - - ulong availaibleSampleCount = sampleCount; - - bool needUpdate = false; - - while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer)) - { - ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed); - ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount); - - ulong currentSamplePlayed = - Interlocked.Add(ref driverBuffer.SamplePlayed, playedAudioBufferSampleCount); - availaibleSampleCount -= playedAudioBufferSampleCount; - - if (currentSamplePlayed == driverBuffer.SampleCount) - { - _queuedBuffers.TryDequeue(out _); - - needUpdate = true; - } - - Interlocked.Add(ref _playedSampleCount, playedAudioBufferSampleCount); - } - - // Notify the output if needed. - if (needUpdate) - { - _updateRequiredEvent.Set(); - } - } - public override ulong GetPlayedSampleCount() { return Interlocked.Read(ref _playedSampleCount); @@ -164,27 +80,21 @@ namespace Ryujinx.Audio.Backends.SDL3 EnsureAudioStreamSetup(buffer); if (_outputStream != 0) { - SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer)); - - _ringBuffer.Write(buffer.Data, 0, buffer.Data.Length); - int MinimumAudio = int.MaxValue; // 8000 float samples per second, half a second. - // SDL_ResumeAudioStreamDevice(_outputStream); - Console.WriteLine(SDL_GetAudioStreamAvailable(_outputStream)); - if (SDL_GetAudioStreamAvailable(_outputStream) < MinimumAudio) + if (SDL_GetAudioStreamAvailable(_outputStream) < int.MaxValue) { unsafe { fixed (byte* samplesPtr = buffer.Data) { - IntPtr buffer2 = (IntPtr)samplesPtr; - - SDL_PutAudioStreamData(_outputStream, buffer2, buffer.Data.Length); - + var len = buffer.Data.Length; + IntPtr src = (IntPtr)samplesPtr; + byte* dst = stackalloc byte[len]; + IntPtr dstPtr = (IntPtr)dst; + SDL_MixAudio(dstPtr, src, _nativeSampleFormat, (uint)len, _driver.Volume); + SDL_PutAudioStreamData(_outputStream, dstPtr, len); } } } - - _queuedBuffers.Enqueue(driverBuffer); } else { @@ -229,12 +139,7 @@ namespace Ryujinx.Audio.Backends.SDL3 public override bool WasBufferFullyConsumed(AudioBuffer buffer) { - if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer)) - { - return true; - } - - return driverBuffer.DriverIdentifier != buffer.DataPointer; + return true; } protected virtual void Dispose(bool disposing) diff --git a/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs b/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs index 02a304aaf..ca5e00f0d 100644 --- a/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs +++ b/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs @@ -8,7 +8,6 @@ namespace Ryujinx.Common.Configuration.Hid { Invalid, WindowKeyboard, - GamepadSDL2, GamepadSDL3 } } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 221c898ea..00182348b 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -4222,6 +4222,31 @@ "zh_TW": "" } }, + { + "ID": "SettingsTabSystemAudioBackendSDL3", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "SDL3", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabSystemHacks", "Translations": { diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs index 7d75ac7c1..86df593d1 100644 --- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs +++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs @@ -157,7 +157,7 @@ namespace Ryujinx.Headless config = new StandardControllerInputConfig { Version = InputConfig.CurrentVersion, - Backend = InputBackendType.GamepadSDL2, + Backend = InputBackendType.GamepadSDL3, Id = null, ControllerType = ControllerType.JoyconPair, DeadzoneLeft = 0.1f, diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index 833670bdc..c03f58a22 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -491,7 +491,7 @@ namespace Ryujinx.Ava.UI.Models.Input var config = new StandardControllerInputConfig { Id = Id, - Backend = InputBackendType.GamepadSDL2, + Backend = InputBackendType.GamepadSDL3, PlayerIndex = PlayerIndex, ControllerType = ControllerType, LeftJoycon = new LeftJoyconCommonConfig diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 7f5f1aba0..130c9eeb3 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -579,7 +579,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input config = new StandardControllerInputConfig { Version = InputConfig.CurrentVersion, - Backend = InputBackendType.GamepadSDL2, + Backend = InputBackendType.GamepadSDL3, Id = id, ControllerType = ControllerType.ProController, DeadzoneLeft = 0.1f, diff --git a/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml index 6f31d76ed..52fb12abf 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml @@ -48,8 +48,7 @@ - - +