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> _commands;
  11. public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
  12. private int _sampleRate;
  13. private int _channelsCount;
  14. private OpusDecoder _decoder;
  15. public IHardwareOpusDecoder(int sampleRate, int channelsCount)
  16. {
  17. _commands = new Dictionary<int, ServiceProcessRequest>
  18. {
  19. { 0, DecodeInterleaved },
  20. { 4, DecodeInterleavedWithPerf }
  21. };
  22. _sampleRate = sampleRate;
  23. _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. }