 456fc04007
			
		
	
	
		456fc04007
		
			
		
	
	
	
	
		
			
			* Better SDL2 Audio Init Error Logging * Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs Co-authored-by: Mary-nyan <thog@protonmail.com> * Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs Co-authored-by: Mary-nyan <thog@protonmail.com> * Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs Co-authored-by: Mary-nyan <thog@protonmail.com> * Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update SDL2HardwareDeviceDriver.cs * Update SDL2HardwareDeviceDriver.cs Co-authored-by: Mary-nyan <thog@protonmail.com> Co-authored-by: Ac_K <Acoustik666@gmail.com>
		
			
				
	
	
		
			176 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Ryujinx.Audio.Common;
 | |
| using Ryujinx.Audio.Integration;
 | |
| using Ryujinx.Common.Logging;
 | |
| using Ryujinx.Memory;
 | |
| using Ryujinx.SDL2.Common;
 | |
| using System;
 | |
| using System.Collections.Concurrent;
 | |
| using System.Threading;
 | |
| 
 | |
| using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
 | |
| using static SDL2.SDL;
 | |
| 
 | |
| namespace Ryujinx.Audio.Backends.SDL2
 | |
| {
 | |
|     public class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
 | |
|     {
 | |
|         private readonly ManualResetEvent _updateRequiredEvent;
 | |
|         private readonly ManualResetEvent _pauseEvent;
 | |
|         private readonly ConcurrentDictionary<SDL2HardwareDeviceSession, byte> _sessions;
 | |
| 
 | |
|         public SDL2HardwareDeviceDriver()
 | |
|         {
 | |
|             _updateRequiredEvent = new ManualResetEvent(false);
 | |
|             _pauseEvent = new ManualResetEvent(true);
 | |
|             _sessions = new ConcurrentDictionary<SDL2HardwareDeviceSession, byte>();
 | |
| 
 | |
|             SDL2Driver.Instance.Initialize();
 | |
|         }
 | |
| 
 | |
|         public static bool IsSupported => IsSupportedInternal();
 | |
| 
 | |
|         private static bool IsSupportedInternal()
 | |
|         {
 | |
|             uint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
 | |
| 
 | |
|             if (device != 0)
 | |
|             {
 | |
|                 SDL_CloseAudioDevice(device);
 | |
|             }
 | |
| 
 | |
|             return device != 0;
 | |
|         }
 | |
| 
 | |
|         public ManualResetEvent GetUpdateRequiredEvent()
 | |
|         {
 | |
|             return _updateRequiredEvent;
 | |
|         }
 | |
| 
 | |
|         public ManualResetEvent GetPauseEvent()
 | |
|         {
 | |
|             return _pauseEvent;
 | |
|         }
 | |
| 
 | |
|         public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
 | |
|         {
 | |
|             if (channelCount == 0)
 | |
|             {
 | |
|                 channelCount = 2;
 | |
|             }
 | |
| 
 | |
|             if (sampleRate == 0)
 | |
|             {
 | |
|                 sampleRate = Constants.TargetSampleRate;
 | |
|             }
 | |
| 
 | |
|             if (direction != Direction.Output)
 | |
|             {
 | |
|                 throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
 | |
|             }
 | |
| 
 | |
|             SDL2HardwareDeviceSession session = new SDL2HardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
 | |
| 
 | |
|             _sessions.TryAdd(session, 0);
 | |
| 
 | |
|             return session;
 | |
|         }
 | |
| 
 | |
|         internal bool Unregister(SDL2HardwareDeviceSession session)
 | |
|         {
 | |
|             return _sessions.TryRemove(session, out _);
 | |
|         }
 | |
| 
 | |
|         private static SDL_AudioSpec GetSDL2Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount)
 | |
|         {
 | |
|             return new SDL_AudioSpec
 | |
|             {
 | |
|                 channels = (byte)requestedChannelCount,
 | |
|                 format = GetSDL2Format(requestedSampleFormat),
 | |
|                 freq = (int)requestedSampleRate,
 | |
|                 samples = (ushort)sampleCount
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         internal static ushort GetSDL2Format(SampleFormat format)
 | |
|         {
 | |
|             return format switch
 | |
|             {
 | |
|                 SampleFormat.PcmInt8 => AUDIO_S8,
 | |
|                 SampleFormat.PcmInt16 => AUDIO_S16,
 | |
|                 SampleFormat.PcmInt32 => AUDIO_S32,
 | |
|                 SampleFormat.PcmFloat => AUDIO_F32,
 | |
|                 _ => throw new ArgumentException($"Unsupported sample format {format}"),
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         internal static uint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL_AudioCallback callback)
 | |
|         {
 | |
|             SDL_AudioSpec desired = GetSDL2Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount, sampleCount);
 | |
| 
 | |
|             desired.callback = callback;
 | |
| 
 | |
|             uint device = SDL_OpenAudioDevice(IntPtr.Zero, 0, ref desired, out SDL_AudioSpec got, 0);
 | |
| 
 | |
|             if (device == 0)
 | |
|             {
 | |
|                 Logger.Error?.Print(LogClass.Application, 
 | |
|                     $"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
 | |
| 
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             bool isValid = got.format == desired.format && got.freq == desired.freq && got.channels == desired.channels;
 | |
| 
 | |
|             if (!isValid)
 | |
|             {
 | |
|                 Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
 | |
|                 SDL_CloseAudioDevice(device);
 | |
| 
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             return device;
 | |
|         }
 | |
| 
 | |
|         public void Dispose()
 | |
|         {
 | |
|             Dispose(true);
 | |
|         }
 | |
| 
 | |
|         protected virtual void Dispose(bool disposing)
 | |
|         {
 | |
|             if (disposing)
 | |
|             {
 | |
|                 foreach (SDL2HardwareDeviceSession session in _sessions.Keys)
 | |
|                 {
 | |
|                     session.Dispose();
 | |
|                 }
 | |
| 
 | |
|                 SDL2Driver.Instance.Dispose();
 | |
| 
 | |
|                 _pauseEvent.Dispose();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public bool SupportsSampleRate(uint sampleRate)
 | |
|         {
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public bool SupportsSampleFormat(SampleFormat sampleFormat)
 | |
|         {
 | |
|             return sampleFormat != SampleFormat.PcmInt24;
 | |
|         }
 | |
| 
 | |
|         public bool SupportsChannelCount(uint channelCount)
 | |
|         {
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public bool SupportsDirection(Direction direction)
 | |
|         {
 | |
|             // TODO: add direction input when supported.
 | |
|             return direction == Direction.Output;
 | |
|         }
 | |
|     }
 | |
| }
 |