IHardwareOpusDecoder.cs 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using Concentus.Structs;
  2. using Ryujinx.HLE.HOS.Ipc;
  3. using System.Collections.Generic;
  4. using static Ryujinx.HLE.HOS.ErrorCode;
  5. namespace Ryujinx.HLE.HOS.Services.Aud
  6. {
  7. class IHardwareOpusDecoder : IpcService
  8. {
  9. private const int FixedSampleRate = 48000;
  10. private Dictionary<int, ServiceProcessRequest> m_Commands;
  11. public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
  12. private int SampleRate;
  13. private int ChannelsCount;
  14. private OpusDecoder Decoder;
  15. public IHardwareOpusDecoder(int SampleRate, int ChannelsCount)
  16. {
  17. m_Commands = new Dictionary<int, ServiceProcessRequest>()
  18. {
  19. { 0, DecodeInterleaved },
  20. { 4, DecodeInterleavedWithPerf }
  21. };
  22. this.SampleRate = SampleRate;
  23. this.ChannelsCount = ChannelsCount;
  24. Decoder = new OpusDecoder(FixedSampleRate, ChannelsCount);
  25. }
  26. public long DecodeInterleavedWithPerf(ServiceCtx Context)
  27. {
  28. long Result = DecodeInterleaved(Context);
  29. //TODO: Figure out what this value is.
  30. //According to switchbrew, it is now used.
  31. Context.ResponseData.Write(0L);
  32. return Result;
  33. }
  34. public long DecodeInterleaved(ServiceCtx Context)
  35. {
  36. long InPosition = Context.Request.SendBuff[0].Position;
  37. long InSize = Context.Request.SendBuff[0].Size;
  38. if (InSize < 8)
  39. {
  40. return MakeError(ErrorModule.Audio, AudErr.OpusInvalidInput);
  41. }
  42. long OutPosition = Context.Request.ReceiveBuff[0].Position;
  43. long OutSize = Context.Request.ReceiveBuff[0].Size;
  44. byte[] OpusData = Context.Memory.ReadBytes(InPosition, InSize);
  45. int Processed = ((OpusData[0] << 24) |
  46. (OpusData[1] << 16) |
  47. (OpusData[2] << 8) |
  48. (OpusData[3] << 0)) + 8;
  49. if ((uint)Processed > (ulong)InSize)
  50. {
  51. return MakeError(ErrorModule.Audio, AudErr.OpusInvalidInput);
  52. }
  53. short[] Pcm = new short[OutSize / 2];
  54. int FrameSize = Pcm.Length / (ChannelsCount * 2);
  55. int Samples = Decoder.Decode(OpusData, 0, OpusData.Length, Pcm, 0, FrameSize);
  56. foreach (short Sample in Pcm)
  57. {
  58. Context.Memory.WriteInt16(OutPosition, Sample);
  59. OutPosition += 2;
  60. }
  61. Context.ResponseData.Write(Processed);
  62. Context.ResponseData.Write(Samples);
  63. return 0;
  64. }
  65. }
  66. }