Refactoring commands handling (#728)

* Refactoring commands handling

- Use Reflection to handle commands ID.
- Add all symbols (from SwIPC so not all time accurate).
- Re-sort some services commands methods.
- Some cleanup.
- Keep some empty constructor for consistency.

* Fix order in IProfile
This commit is contained in:
Ac_K 2019-07-12 03:13:43 +02:00 committed by gdkchan
parent f723f6f39a
commit 560ccbeb2d
99 changed files with 1035 additions and 1983 deletions

View file

@ -4,42 +4,24 @@ using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
{
class IAudioOut : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
private IAalOutput _audioOut;
private KEvent _releaseEvent;
private int _track;
private KEvent _releaseEvent;
private int _track;
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, GetAudioOutState },
{ 1, StartAudioOut },
{ 2, StopAudioOut },
{ 3, AppendAudioOutBuffer },
{ 4, RegisterBufferEvent },
{ 5, GetReleasedAudioOutBuffer },
{ 6, ContainsAudioOutBuffer },
{ 7, AppendAudioOutBufferAuto },
{ 8, GetReleasedAudioOutBufferAuto }
};
_audioOut = audioOut;
_releaseEvent = releaseEvent;
_track = track;
}
[Command(0)]
// GetAudioOutState() -> u32 state
public long GetAudioOutState(ServiceCtx context)
{
context.ResponseData.Write((int)_audioOut.GetState(_track));
@ -47,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(1)]
// StartAudioOut()
public long StartAudioOut(ServiceCtx context)
{
_audioOut.Start(_track);
@ -54,6 +38,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(2)]
// StopAudioOut()
public long StopAudioOut(ServiceCtx context)
{
_audioOut.Stop(_track);
@ -61,11 +47,15 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(3)]
// AppendAudioOutBuffer(u64 tag, buffer<nn::audio::AudioOutBuffer, 5>)
public long AppendAudioOutBuffer(ServiceCtx context)
{
return AppendAudioOutBufferImpl(context, context.Request.SendBuff[0].Position);
}
[Command(4)]
// RegisterBufferEvent() -> handle<copy>
public long RegisterBufferEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
@ -78,6 +68,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(5)]
// GetReleasedAudioOutBuffer() -> (u32 count, buffer<nn::audio::AudioOutBuffer, 6>)
public long GetReleasedAudioOutBuffer(ServiceCtx context)
{
long position = context.Request.ReceiveBuff[0].Position;
@ -86,6 +78,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return GetReleasedAudioOutBufferImpl(context, position, size);
}
[Command(6)]
// ContainsAudioOutBuffer(u64 tag) -> b8
public long ContainsAudioOutBuffer(ServiceCtx context)
{
long tag = context.RequestData.ReadInt64();
@ -95,6 +89,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(7)] // 3.0.0+
// AppendAudioOutBufferAuto(u64 tag, buffer<nn::audio::AudioOutBuffer, 0x21>)
public long AppendAudioOutBufferAuto(ServiceCtx context)
{
(long position, long size) = context.Request.GetBufferType0x21();
@ -119,6 +115,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
return 0;
}
[Command(8)] // 3.0.0+
// GetReleasedAudioOutBufferAuto() -> (u32 count, buffer<nn::audio::AudioOutBuffer, 0x22>)
public long GetReleasedAudioOutBufferAuto(ServiceCtx context)
{
(long position, long size) = context.Request.GetBufferType0x22();
@ -162,4 +160,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
}
}
}
}
}

View file

@ -7,7 +7,6 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.Utilities;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
@ -23,10 +22,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
// high latency).
private const int MixBufferSamplesCount = 960;
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
private KEvent _updateEvent;
private MemoryManager _memory;
@ -49,18 +44,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
IAalOutput audioOut,
AudioRendererParameter Params)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, GetSampleRate },
{ 1, GetSampleCount },
{ 2, GetMixBufferCount },
{ 3, GetState },
{ 4, RequestUpdateAudioRenderer },
{ 5, StartAudioRenderer },
{ 6, StopAudioRenderer },
{ 7, QuerySystemEvent }
};
_updateEvent = new KEvent(system);
_memory = memory;
@ -81,7 +64,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
_playState = PlayState.Stopped;
}
// GetSampleRate() -> u32
[Command(0)]
// GetSampleRate() -> u32
public long GetSampleRate(ServiceCtx context)
{
context.ResponseData.Write(_params.SampleRate);
@ -89,7 +73,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
// GetSampleCount() -> u32
[Command(1)]
// GetSampleCount() -> u32
public long GetSampleCount(ServiceCtx context)
{
context.ResponseData.Write(_params.SampleCount);
@ -97,6 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
[Command(2)]
// GetMixBufferCount() -> u32
public long GetMixBufferCount(ServiceCtx context)
{
@ -105,6 +91,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
[Command(3)]
// GetState() -> u32
private long GetState(ServiceCtx context)
{
@ -141,6 +128,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
_audioOut.Start(_track);
}
[Command(4)]
// RequestUpdateAudioRenderer(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 5>)
// -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>)
public long RequestUpdateAudioRenderer(ServiceCtx context)
{
long outputPosition = context.Request.ReceiveBuff[0].Position;
@ -247,6 +237,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
[Command(5)]
// Start()
public long StartAudioRenderer(ServiceCtx context)
{
Logger.PrintStub(LogClass.ServiceAudio);
@ -256,6 +248,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
[Command(6)]
// Stop()
public long StopAudioRenderer(ServiceCtx context)
{
Logger.PrintStub(LogClass.ServiceAudio);
@ -265,6 +259,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
return 0;
}
[Command(7)]
// QuerySystemEvent() -> handle<copy, event>
public long QuerySystemEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success)
@ -405,4 +401,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
}
}
}
}
}

View file

@ -4,42 +4,24 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.SystemState;
using System;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Aud
{
class IAudioDevice : IpcService
{
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
private KEvent _systemEvent;
public IAudioDevice(Horizon system)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, ListAudioDeviceName },
{ 1, SetAudioDeviceOutputVolume },
{ 3, GetActiveAudioDeviceName },
{ 4, QueryAudioDeviceSystemEvent },
{ 5, GetActiveChannelCount },
{ 6, ListAudioDeviceNameAuto },
{ 7, SetAudioDeviceOutputVolumeAuto },
{ 8, GetAudioDeviceOutputVolumeAuto },
{ 10, GetActiveAudioDeviceNameAuto },
{ 11, QueryAudioDeviceInputEvent },
{ 12, QueryAudioDeviceOutputEvent }
};
_systemEvent = new KEvent(system);
// TODO: We shouldn't be signaling this here.
_systemEvent.ReadableEvent.Signal();
}
[Command(0)]
// ListAudioDeviceName() -> (u32, buffer<bytes, 6>)
public long ListAudioDeviceName(ServiceCtx context)
{
string[] deviceNames = SystemStateMgr.AudioOutputs;
@ -70,6 +52,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(1)]
// SetAudioDeviceOutputVolume(u32, buffer<bytes, 5>)
public long SetAudioDeviceOutputVolume(ServiceCtx context)
{
float volume = context.RequestData.ReadSingle();
@ -86,6 +70,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(3)]
// GetActiveAudioDeviceName() -> buffer<bytes, 6>
public long GetActiveAudioDeviceName(ServiceCtx context)
{
string name = context.Device.System.State.ActiveAudioOutput;
@ -107,6 +93,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(4)]
// QueryAudioDeviceSystemEvent() -> handle<copy, event>
public long QueryAudioDeviceSystemEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@ -121,6 +109,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(5)]
// GetActiveChannelCount() -> u32
public long GetActiveChannelCount(ServiceCtx context)
{
context.ResponseData.Write(2);
@ -130,6 +120,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(6)]
// ListAudioDeviceNameAuto() -> (u32, buffer<bytes, 0x22>)
public long ListAudioDeviceNameAuto(ServiceCtx context)
{
string[] deviceNames = SystemStateMgr.AudioOutputs;
@ -159,6 +151,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(7)]
// SetAudioDeviceOutputVolumeAuto(u32, buffer<bytes, 0x21>)
public long SetAudioDeviceOutputVolumeAuto(ServiceCtx context)
{
float volume = context.RequestData.ReadSingle();
@ -174,6 +168,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(8)]
// GetAudioDeviceOutputVolumeAuto(buffer<bytes, 0x21>) -> u32
public long GetAudioDeviceOutputVolumeAuto(ServiceCtx context)
{
context.ResponseData.Write(1f);
@ -183,6 +179,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(10)]
// GetActiveAudioDeviceNameAuto() -> buffer<bytes, 0x22>
public long GetActiveAudioDeviceNameAuto(ServiceCtx context)
{
string name = context.Device.System.State.ActiveAudioOutput;
@ -203,6 +201,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(11)]
// QueryAudioDeviceInputEvent() -> handle<copy, event>
public long QueryAudioDeviceInputEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@ -217,6 +217,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(12)]
// QueryAudioDeviceOutputEvent() -> handle<copy, event>
public long QueryAudioDeviceOutputEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@ -231,4 +233,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
}
}
}

View file

@ -1,10 +1,8 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Aud.AudioOut;
using System.Collections.Generic;
using System.Text;
using static Ryujinx.HLE.HOS.ErrorCode;
@ -14,27 +12,14 @@ namespace Ryujinx.HLE.HOS.Services.Aud
[Service("audout:u")]
class IAudioOutManager : IpcService
{
private const string DefaultAudioOutput = "DeviceOut";
private const string DefaultAudioOutput = "DeviceOut";
private const int DefaultSampleRate = 48000;
private const int DefaultChannelsCount = 2;
private const int DefaultSampleRate = 48000;
private const int DefaultChannelsCount = 2;
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
public IAudioOutManager(ServiceCtx context)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, ListAudioOuts },
{ 1, OpenAudioOut },
{ 2, ListAudioOutsAuto },
{ 3, OpenAudioOutAuto }
};
}
public IAudioOutManager(ServiceCtx context) { }
[Command(0)]
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
public long ListAudioOuts(ServiceCtx context)
{
return ListAudioOutsImpl(
@ -43,6 +28,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud
context.Request.ReceiveBuff[0].Size);
}
[Command(1)]
// OpenAudioOut(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle<copy, process>, buffer<bytes, 5> name_in)
// -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 6> name_out)
public long OpenAudioOut(ServiceCtx context)
{
return OpenAudioOutImpl(
@ -53,6 +41,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
context.Request.ReceiveBuff[0].Size);
}
[Command(2)] // 3.0.0+
// ListAudioOutsAuto() -> (u32 count, buffer<bytes, 0x22>)
public long ListAudioOutsAuto(ServiceCtx context)
{
(long recvPosition, long recvSize) = context.Request.GetBufferType0x22();
@ -60,6 +50,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return ListAudioOutsImpl(context, recvPosition, recvSize);
}
[Command(3)] // 3.0.0+
// OpenAudioOutAuto(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle<copy, process>, buffer<bytes, 0x21>)
// -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 0x22> name_out)
public long OpenAudioOutAuto(ServiceCtx context)
{
(long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
@ -168,4 +161,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
}
}
}

View file

@ -1,9 +1,7 @@
using Ryujinx.Audio;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer;
using Ryujinx.HLE.Utilities;
using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
@ -21,21 +19,11 @@ namespace Ryujinx.HLE.HOS.Services.Aud
public const int RevMagic = Rev0Magic + (Rev << 24);
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
public IAudioRendererManager(ServiceCtx context)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, OpenAudioRenderer },
{ 1, GetAudioRendererWorkBufferSize },
{ 2, GetAudioDeviceService },
{ 4, GetAudioDeviceServiceWithRevisionInfo }
};
}
public IAudioRendererManager(ServiceCtx context) { }
[Command(0)]
// OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle<copy>, handle<copy>)
// -> object<nn::audio::detail::IAudioRenderer>
public long OpenAudioRenderer(ServiceCtx context)
{
IAalOutput audioOut = context.Device.AudioOut;
@ -51,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(1)]
// GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64
public long GetAudioRendererWorkBufferSize(ServiceCtx context)
{
AudioRendererParameter Params = GetAudioRendererParameter(context);
@ -178,6 +168,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return result / 8;
}
[Command(2)]
// GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
public long GetAudioDeviceService(ServiceCtx context)
{
@ -188,6 +179,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(4)] // 4.0.0+
// GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
{

View file

@ -1,6 +1,4 @@
using Concentus.Structs;
using Ryujinx.HLE.HOS.Ipc;
using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
@ -10,10 +8,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud
{
private const int FixedSampleRate = 48000;
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
private int _sampleRate;
private int _channelsCount;
@ -21,29 +15,14 @@ namespace Ryujinx.HLE.HOS.Services.Aud
public IHardwareOpusDecoder(int sampleRate, int channelsCount)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, DecodeInterleaved },
{ 4, DecodeInterleavedWithPerf }
};
_sampleRate = sampleRate;
_channelsCount = channelsCount;
_decoder = new OpusDecoder(FixedSampleRate, channelsCount);
}
public long DecodeInterleavedWithPerf(ServiceCtx context)
{
long result = DecodeInterleaved(context);
// TODO: Figure out what this value is.
// According to switchbrew, it is now used.
context.ResponseData.Write(0L);
return result;
}
[Command(0)]
// DecodeInterleaved(buffer<unknown, 5>) -> (u32, u32, buffer<unknown, 6>)
public long DecodeInterleaved(ServiceCtx context)
{
long inPosition = context.Request.SendBuff[0].Position;
@ -87,5 +66,18 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(4)]
// DecodeInterleavedWithPerf(buffer<unknown, 5>) -> (u32, u32, u64, buffer<unknown, 0x46>)
public long DecodeInterleavedWithPerf(ServiceCtx context)
{
long result = DecodeInterleaved(context);
// TODO: Figure out what this value is.
// According to switchbrew, it is now used.
context.ResponseData.Write(0L);
return result;
}
}
}
}

View file

@ -1,24 +1,12 @@
using Ryujinx.HLE.HOS.Ipc;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Aud
{
[Service("hwopus")]
class IHardwareOpusDecoderManager : IpcService
{
private Dictionary<int, ServiceProcessRequest> _commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
public IHardwareOpusDecoderManager(ServiceCtx context)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
{ 0, Initialize },
{ 1, GetWorkBufferSize }
};
}
public IHardwareOpusDecoderManager(ServiceCtx context) { }
[Command(0)]
// Initialize(bytes<8, 4>, u32, handle<copy>) -> object<nn::codec::detail::IHardwareOpusDecoder>
public long Initialize(ServiceCtx context)
{
int sampleRate = context.RequestData.ReadInt32();
@ -29,6 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
return 0;
}
[Command(1)]
// GetWorkBufferSize(bytes<8, 4>) -> u32
public long GetWorkBufferSize(ServiceCtx context)
{
// Note: The sample rate is ignored because it is fixed to 48KHz.
@ -70,4 +60,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
celtSigSize;
}
}
}
}