/ src / Ryujinx.Audio / Backends / CompatLayer / CompatLayerHardwareDeviceSession.cs
CompatLayerHardwareDeviceSession.cs
  1  using Ryujinx.Audio.Backends.Common;
  2  using Ryujinx.Audio.Common;
  3  using Ryujinx.Audio.Renderer.Dsp;
  4  using System;
  5  using System.Runtime.InteropServices;
  6  
  7  namespace Ryujinx.Audio.Backends.CompatLayer
  8  {
  9      class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase
 10      {
 11          private readonly HardwareDeviceSessionOutputBase _realSession;
 12          private readonly SampleFormat _userSampleFormat;
 13          private readonly uint _userChannelCount;
 14  
 15          public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, SampleFormat userSampleFormat, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount)
 16          {
 17              _realSession = realSession;
 18              _userSampleFormat = userSampleFormat;
 19              _userChannelCount = userChannelCount;
 20          }
 21  
 22          public override void Dispose()
 23          {
 24              _realSession.Dispose();
 25          }
 26  
 27          public override ulong GetPlayedSampleCount()
 28          {
 29              return _realSession.GetPlayedSampleCount();
 30          }
 31  
 32          public override float GetVolume()
 33          {
 34              return _realSession.GetVolume();
 35          }
 36  
 37          public override void PrepareToClose()
 38          {
 39              _realSession.PrepareToClose();
 40          }
 41  
 42          public override void QueueBuffer(AudioBuffer buffer)
 43          {
 44              SampleFormat realSampleFormat = _realSession.RequestedSampleFormat;
 45  
 46              if (_userSampleFormat != realSampleFormat)
 47              {
 48                  if (_userSampleFormat != SampleFormat.PcmInt16)
 49                  {
 50                      throw new NotImplementedException("Converting formats other than PCM16 is not supported.");
 51                  }
 52  
 53                  int userSampleCount = buffer.Data.Length / BackendHelper.GetSampleSize(_userSampleFormat);
 54  
 55                  ReadOnlySpan<short> samples = MemoryMarshal.Cast<byte, short>(buffer.Data);
 56                  byte[] convertedSamples = new byte[BackendHelper.GetSampleSize(realSampleFormat) * userSampleCount];
 57  
 58                  switch (realSampleFormat)
 59                  {
 60                      case SampleFormat.PcmInt8:
 61                          PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
 62                          break;
 63                      case SampleFormat.PcmInt24:
 64                          PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
 65                          break;
 66                      case SampleFormat.PcmInt32:
 67                          PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
 68                          break;
 69                      case SampleFormat.PcmFloat:
 70                          PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
 71                          break;
 72                      default:
 73                          throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
 74                  }
 75  
 76                  buffer.Data = convertedSamples;
 77              }
 78  
 79              _realSession.QueueBuffer(buffer);
 80          }
 81  
 82          public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
 83          {
 84              if (samples == null)
 85              {
 86                  return false;
 87              }
 88  
 89              if (_userChannelCount != _realSession.RequestedChannelCount)
 90              {
 91                  if (_userSampleFormat != SampleFormat.PcmInt16)
 92                  {
 93                      throw new NotImplementedException("Downmixing formats other than PCM16 is not supported.");
 94                  }
 95  
 96                  ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples);
 97  
 98                  if (_userChannelCount == 6)
 99                  {
100                      samplesPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16);
101  
102                      if (_realSession.RequestedChannelCount == 1)
103                      {
104                          samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
105                      }
106                  }
107                  else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1)
108                  {
109                      samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
110                  }
111                  else
112                  {
113                      throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented.");
114                  }
115  
116                  samples = MemoryMarshal.Cast<short, byte>(samplesPCM16).ToArray();
117              }
118  
119              AudioBuffer fakeBuffer = new()
120              {
121                  BufferTag = buffer.BufferTag,
122                  DataPointer = buffer.DataPointer,
123                  DataSize = (ulong)samples.Length,
124              };
125  
126              bool result = _realSession.RegisterBuffer(fakeBuffer, samples);
127  
128              if (result)
129              {
130                  buffer.Data = fakeBuffer.Data;
131                  buffer.DataSize = fakeBuffer.DataSize;
132              }
133  
134              return result;
135          }
136  
137          public override void SetVolume(float volume)
138          {
139              _realSession.SetVolume(volume);
140          }
141  
142          public override void Start()
143          {
144              _realSession.Start();
145          }
146  
147          public override void Stop()
148          {
149              _realSession.Stop();
150          }
151  
152          public override void UnregisterBuffer(AudioBuffer buffer)
153          {
154              _realSession.UnregisterBuffer(buffer);
155          }
156  
157          public override bool WasBufferFullyConsumed(AudioBuffer buffer)
158          {
159              return _realSession.WasBufferFullyConsumed(buffer);
160          }
161      }
162  }