AudioRendererServer.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Common.Memory;
  3. using Ryujinx.HLE.HOS.Ipc;
  4. using Ryujinx.HLE.HOS.Kernel.Threading;
  5. using Ryujinx.Horizon.Common;
  6. using System;
  7. using System.Buffers;
  8. namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
  9. {
  10. class AudioRendererServer : DisposableIpcService
  11. {
  12. private IAudioRenderer _impl;
  13. public AudioRendererServer(IAudioRenderer impl)
  14. {
  15. _impl = impl;
  16. }
  17. [CommandCmif(0)]
  18. // GetSampleRate() -> u32
  19. public ResultCode GetSampleRate(ServiceCtx context)
  20. {
  21. context.ResponseData.Write(_impl.GetSampleRate());
  22. return ResultCode.Success;
  23. }
  24. [CommandCmif(1)]
  25. // GetSampleCount() -> u32
  26. public ResultCode GetSampleCount(ServiceCtx context)
  27. {
  28. context.ResponseData.Write(_impl.GetSampleCount());
  29. return ResultCode.Success;
  30. }
  31. [CommandCmif(2)]
  32. // GetMixBufferCount() -> u32
  33. public ResultCode GetMixBufferCount(ServiceCtx context)
  34. {
  35. context.ResponseData.Write(_impl.GetMixBufferCount());
  36. return ResultCode.Success;
  37. }
  38. [CommandCmif(3)]
  39. // GetState() -> u32
  40. public ResultCode GetState(ServiceCtx context)
  41. {
  42. context.ResponseData.Write(_impl.GetState());
  43. return ResultCode.Success;
  44. }
  45. [CommandCmif(4)]
  46. // RequestUpdate(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 5> input)
  47. // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6> output, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6> performanceOutput)
  48. public ResultCode RequestUpdate(ServiceCtx context)
  49. {
  50. ulong inputPosition = context.Request.SendBuff[0].Position;
  51. ulong inputSize = context.Request.SendBuff[0].Size;
  52. ulong outputPosition = context.Request.ReceiveBuff[0].Position;
  53. ulong outputSize = context.Request.ReceiveBuff[0].Size;
  54. ulong performanceOutputPosition = context.Request.ReceiveBuff[1].Position;
  55. ulong performanceOutputSize = context.Request.ReceiveBuff[1].Size;
  56. ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray();
  57. using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.Shared.RentCleared(outputSize))
  58. using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.Shared.RentCleared(performanceOutputSize))
  59. {
  60. Memory<byte> output = outputOwner.Memory;
  61. Memory<byte> performanceOutput = performanceOutputOwner.Memory;
  62. using MemoryHandle outputHandle = output.Pin();
  63. using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
  64. ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
  65. if (result == ResultCode.Success)
  66. {
  67. context.Memory.Write(outputPosition, output.Span);
  68. context.Memory.Write(performanceOutputPosition, performanceOutput.Span);
  69. }
  70. else
  71. {
  72. Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}");
  73. }
  74. return result;
  75. }
  76. }
  77. [CommandCmif(5)]
  78. // Start()
  79. public ResultCode Start(ServiceCtx context)
  80. {
  81. return _impl.Start();
  82. }
  83. [CommandCmif(6)]
  84. // Stop()
  85. public ResultCode Stop(ServiceCtx context)
  86. {
  87. return _impl.Stop();
  88. }
  89. [CommandCmif(7)]
  90. // QuerySystemEvent() -> handle<copy, event>
  91. public ResultCode QuerySystemEvent(ServiceCtx context)
  92. {
  93. ResultCode result = _impl.QuerySystemEvent(out KEvent systemEvent);
  94. if (result == ResultCode.Success)
  95. {
  96. if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != Result.Success)
  97. {
  98. throw new InvalidOperationException("Out of handles!");
  99. }
  100. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
  101. }
  102. return result;
  103. }
  104. [CommandCmif(8)]
  105. // SetAudioRendererRenderingTimeLimit(u32 limit)
  106. public ResultCode SetAudioRendererRenderingTimeLimit(ServiceCtx context)
  107. {
  108. uint limit = context.RequestData.ReadUInt32();
  109. _impl.SetRenderingTimeLimit(limit);
  110. return ResultCode.Success;
  111. }
  112. [CommandCmif(9)]
  113. // GetAudioRendererRenderingTimeLimit() -> u32 limit
  114. public ResultCode GetAudioRendererRenderingTimeLimit(ServiceCtx context)
  115. {
  116. uint limit = _impl.GetRenderingTimeLimit();
  117. context.ResponseData.Write(limit);
  118. return ResultCode.Success;
  119. }
  120. [CommandCmif(10)] // 3.0.0+
  121. // RequestUpdateAuto(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x21> input)
  122. // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x22> output, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x22> performanceOutput)
  123. public ResultCode RequestUpdateAuto(ServiceCtx context)
  124. {
  125. (ulong inputPosition, ulong inputSize) = context.Request.GetBufferType0x21();
  126. (ulong outputPosition, ulong outputSize) = context.Request.GetBufferType0x22(0);
  127. (ulong performanceOutputPosition, ulong performanceOutputSize) = context.Request.GetBufferType0x22(1);
  128. ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray();
  129. Memory<byte> output = new byte[outputSize];
  130. Memory<byte> performanceOutput = new byte[performanceOutputSize];
  131. using MemoryHandle outputHandle = output.Pin();
  132. using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
  133. ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
  134. if (result == ResultCode.Success)
  135. {
  136. context.Memory.Write(outputPosition, output.Span);
  137. context.Memory.Write(performanceOutputPosition, performanceOutput.Span);
  138. }
  139. return result;
  140. }
  141. [CommandCmif(11)] // 3.0.0+
  142. // ExecuteAudioRendererRendering()
  143. public ResultCode ExecuteAudioRendererRendering(ServiceCtx context)
  144. {
  145. return _impl.ExecuteAudioRendererRendering();
  146. }
  147. [CommandCmif(12)] // 15.0.0+
  148. // SetVoiceDropParameter(f32 voiceDropParameter)
  149. public ResultCode SetVoiceDropParameter(ServiceCtx context)
  150. {
  151. float voiceDropParameter = context.RequestData.ReadSingle();
  152. _impl.SetVoiceDropParameter(voiceDropParameter);
  153. return ResultCode.Success;
  154. }
  155. [CommandCmif(13)] // 15.0.0+
  156. // GetVoiceDropParameter() -> f32 voiceDropParameter
  157. public ResultCode GetVoiceDropParameter(ServiceCtx context)
  158. {
  159. float voiceDropParameter = _impl.GetVoiceDropParameter();
  160. context.ResponseData.Write(voiceDropParameter);
  161. return ResultCode.Success;
  162. }
  163. protected override void Dispose(bool isDisposing)
  164. {
  165. if (isDisposing)
  166. {
  167. _impl.Dispose();
  168. }
  169. }
  170. }
  171. }