Rename Ryujinx.Core to Ryujinx.HLE and add a separate project for a future LLE implementation

This commit is contained in:
gdkchan
2018-06-10 21:46:42 -03:00
parent 518fe799da
commit 76f3b1b3a4
248 changed files with 2266 additions and 2244 deletions

View File

@@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
[StructLayout(LayoutKind.Sequential)]
struct AudioOutData
{
public long NextBufferPtr;
public long SampleBufferPtr;
public long SampleBufferCapacity;
public long SampleBufferSize;
public long SampleBufferInnerOffset;
}
}

View File

@@ -0,0 +1,222 @@
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Handles;
using Ryujinx.HLE.OsHle.Ipc;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
class IAudioDevice : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent SystemEvent;
public IAudioDevice()
{
m_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();
//TODO: We shouldn't be signaling this here.
SystemEvent.WaitEvent.Set();
}
public long ListAudioDeviceName(ServiceCtx Context)
{
string[] DeviceNames = SystemStateMgr.AudioOutputs;
Context.ResponseData.Write(DeviceNames.Length);
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
long BasePosition = Position;
foreach (string Name in DeviceNames)
{
byte[] Buffer = Encoding.ASCII.GetBytes(Name + "\0");
if ((Position - BasePosition) + Buffer.Length > Size)
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
break;
}
Context.Memory.WriteBytes(Position, Buffer);
Position += Buffer.Length;
}
return 0;
}
public long SetAudioDeviceOutputVolume(ServiceCtx Context)
{
float Volume = Context.RequestData.ReadSingle();
long Position = Context.Request.SendBuff[0].Position;
long Size = Context.Request.SendBuff[0].Size;
byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size);
string DeviceName = Encoding.ASCII.GetString(DeviceNameBuffer);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long GetActiveAudioDeviceName(ServiceCtx Context)
{
string Name = Context.Ns.Os.SystemState.ActiveAudioOutput;
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(Name + "\0");
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
{
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
}
else
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
}
return 0;
}
public long QueryAudioDeviceSystemEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long GetActiveChannelCount(ServiceCtx Context)
{
Context.ResponseData.Write(2);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long ListAudioDeviceNameAuto(ServiceCtx Context)
{
string[] DeviceNames = SystemStateMgr.AudioOutputs;
Context.ResponseData.Write(DeviceNames.Length);
(long Position, long Size) = Context.Request.GetBufferType0x22();
long BasePosition = Position;
foreach (string Name in DeviceNames)
{
byte[] Buffer = Encoding.UTF8.GetBytes(Name + '\0');
if ((Position - BasePosition) + Buffer.Length > Size)
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
break;
}
Context.Memory.WriteBytes(Position, Buffer);
Position += Buffer.Length;
}
return 0;
}
public long SetAudioDeviceOutputVolumeAuto(ServiceCtx Context)
{
float Volume = Context.RequestData.ReadSingle();
(long Position, long Size) = Context.Request.GetBufferType0x21();
byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size);
string DeviceName = Encoding.UTF8.GetString(DeviceNameBuffer);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long GetAudioDeviceOutputVolumeAuto(ServiceCtx Context)
{
Context.ResponseData.Write(1f);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long GetActiveAudioDeviceNameAuto(ServiceCtx Context)
{
string Name = Context.Ns.Os.SystemState.ActiveAudioOutput;
(long Position, long Size) = Context.Request.GetBufferType0x22();
byte[] DeviceNameBuffer = Encoding.UTF8.GetBytes(Name + '\0');
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
{
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
}
else
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
}
return 0;
}
public long QueryAudioDeviceInputEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long QueryAudioDeviceOutputEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
}
}

View File

@@ -0,0 +1,154 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Handles;
using Ryujinx.HLE.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
class IAudioOut : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IAalOutput AudioOut;
private KEvent ReleaseEvent;
private int Track;
public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, GetAudioOutState },
{ 1, StartAudioOut },
{ 2, StopAudioOut },
{ 3, AppendAudioOutBuffer },
{ 4, RegisterBufferEvent },
{ 5, GetReleasedAudioOutBuffer },
{ 6, ContainsAudioOutBuffer },
{ 7, AppendAudioOutBufferEx },
{ 8, GetReleasedAudioOutBufferEx }
};
this.AudioOut = AudioOut;
this.ReleaseEvent = ReleaseEvent;
this.Track = Track;
}
public long GetAudioOutState(ServiceCtx Context)
{
Context.ResponseData.Write((int)AudioOut.GetState(Track));
return 0;
}
public long StartAudioOut(ServiceCtx Context)
{
AudioOut.Start(Track);
return 0;
}
public long StopAudioOut(ServiceCtx Context)
{
AudioOut.Stop(Track);
return 0;
}
public long AppendAudioOutBuffer(ServiceCtx Context)
{
long Tag = Context.RequestData.ReadInt64();
AudioOutData Data = AMemoryHelper.Read<AudioOutData>(
Context.Memory,
Context.Request.SendBuff[0].Position);
byte[] Buffer = Context.Memory.ReadBytes(
Data.SampleBufferPtr,
Data.SampleBufferSize);
AudioOut.AppendBuffer(Track, Tag, Buffer);
return 0;
}
public long RegisterBufferEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
{
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
uint Count = (uint)((ulong)Size >> 3);
long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count);
for (uint Index = 0; Index < Count; Index++)
{
long Tag = 0;
if (Index < ReleasedBuffers.Length)
{
Tag = ReleasedBuffers[Index];
}
Context.Memory.WriteInt64(Position + Index * 8, Tag);
}
Context.ResponseData.Write(ReleasedBuffers.Length);
return 0;
}
public long ContainsAudioOutBuffer(ServiceCtx Context)
{
long Tag = Context.RequestData.ReadInt64();
Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0);
return 0;
}
public long AppendAudioOutBufferEx(ServiceCtx Context)
{
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long GetReleasedAudioOutBufferEx(ServiceCtx Context)
{
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
AudioOut.CloseTrack(Track);
ReleaseEvent.Dispose();
}
}
}
}

View File

@@ -0,0 +1,115 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Handles;
using Ryujinx.HLE.OsHle.Ipc;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
class IAudioOutManager : IpcService
{
private const string DefaultAudioOutput = "DeviceOut";
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioOutManager()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, ListAudioOuts },
{ 1, OpenAudioOut }
};
}
public long ListAudioOuts(ServiceCtx Context)
{
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
int NameCount = 0;
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0");
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
{
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
NameCount++;
}
else
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
}
Context.ResponseData.Write(NameCount);
return 0;
}
public long OpenAudioOut(ServiceCtx Context)
{
IAalOutput AudioOut = Context.Ns.AudioOut;
string DeviceName = AMemoryHelper.ReadAsciiString(
Context.Memory,
Context.Request.SendBuff[0].Position,
Context.Request.SendBuff[0].Size);
if (DeviceName == string.Empty)
{
DeviceName = DefaultAudioOutput;
}
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName + "\0");
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
{
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
}
else
{
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
}
int SampleRate = Context.RequestData.ReadInt32();
int Channels = Context.RequestData.ReadInt32();
Channels = (ushort)(Channels >> 16);
if (SampleRate == 0)
{
SampleRate = 48000;
}
if (Channels < 1 || Channels > 2)
{
Channels = 2;
}
KEvent ReleaseEvent = new KEvent();
ReleaseCallback Callback = () =>
{
ReleaseEvent.WaitEvent.Set();
};
int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format);
MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
Context.ResponseData.Write(SampleRate);
Context.ResponseData.Write(Channels);
Context.ResponseData.Write((int)Format);
Context.ResponseData.Write((int)PlaybackState.Stopped);
return 0;
}
}
}

View File

@@ -0,0 +1,92 @@
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Handles;
using Ryujinx.HLE.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
class IAudioRenderer : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent UpdateEvent;
public IAudioRenderer()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 4, RequestUpdateAudioRenderer },
{ 5, StartAudioRenderer },
{ 6, StopAudioRenderer },
{ 7, QuerySystemEvent }
};
UpdateEvent = new KEvent();
}
public long RequestUpdateAudioRenderer(ServiceCtx Context)
{
//(buffer<unknown, 5, 0>) -> (buffer<unknown, 6, 0>, buffer<unknown, 6, 0>)
long Position = Context.Request.ReceiveBuff[0].Position;
//0x40 bytes header
Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section)
Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size?
Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size?
Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size?
Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size?
Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size?
Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header)
for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10)
{
Context.Memory.WriteInt32(Position + Offset, 5);
}
//TODO: We shouldn't be signaling this here.
UpdateEvent.WaitEvent.Set();
return 0;
}
public long StartAudioRenderer(ServiceCtx Context)
{
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long StopAudioRenderer(ServiceCtx Context)
{
Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
return 0;
}
public long QuerySystemEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
UpdateEvent.Dispose();
}
}
}
}

View File

@@ -0,0 +1,135 @@
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.HLE.OsHle.Services.Aud
{
class IAudioRendererManager : IpcService
{
private const int Rev0Magic = ('R' << 0) |
('E' << 8) |
('V' << 16) |
('0' << 24);
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioRendererManager()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, OpenAudioRenderer },
{ 1, GetAudioRendererWorkBufferSize },
{ 2, GetAudioDevice }
};
}
public long OpenAudioRenderer(ServiceCtx Context)
{
//Same buffer as GetAudioRendererWorkBufferSize is receive here.
MakeObject(Context, new IAudioRenderer());
return 0;
}
public long GetAudioRendererWorkBufferSize(ServiceCtx Context)
{
long SampleRate = Context.RequestData.ReadUInt32();
long Unknown4 = Context.RequestData.ReadUInt32();
long Unknown8 = Context.RequestData.ReadUInt32();
long UnknownC = Context.RequestData.ReadUInt32();
long Unknown10 = Context.RequestData.ReadUInt32(); //VoiceCount
long Unknown14 = Context.RequestData.ReadUInt32(); //SinkCount
long Unknown18 = Context.RequestData.ReadUInt32(); //EffectCount
long Unknown1c = Context.RequestData.ReadUInt32(); //Boolean
long Unknown20 = Context.RequestData.ReadUInt32(); //Not used here in FW3.0.1 - Boolean
long Unknown24 = Context.RequestData.ReadUInt32();
long Unknown28 = Context.RequestData.ReadUInt32(); //SplitterCount
long Unknown2c = Context.RequestData.ReadUInt32(); //Not used here in FW3.0.1
int RevMagic = Context.RequestData.ReadInt32();
int Version = (RevMagic - Rev0Magic) >> 24;
if (Version <= 3) //REV3 Max is supported
{
long Size = RoundUp(Unknown8 * 4, 64);
Size += (UnknownC << 10);
Size += (UnknownC + 1) * 0x940;
Size += Unknown10 * 0x3F0;
Size += RoundUp((UnknownC + 1) * 8, 16);
Size += RoundUp(Unknown10 * 8, 16);
Size += RoundUp((0x3C0 * (Unknown14 + UnknownC) + 4 * Unknown4) * (Unknown8 + 6), 64);
Size += 0x2C0 * (Unknown14 + UnknownC) + 0x30 * (Unknown18 + (4 * Unknown10)) + 0x50;
if (Version >= 3) //IsSplitterSupported
{
Size += RoundUp((NodeStatesGetWorkBufferSize((int)UnknownC + 1) + EdgeMatrixGetWorkBufferSize((int)UnknownC + 1)), 16);
Size += 0xE0 * Unknown28 + 0x20 * Unknown24 + RoundUp(Unknown28 * 4, 16);
}
Size = 0x4C0 * Unknown18 + RoundUp(Size, 64) + 0x170 * Unknown14 + ((Unknown10 << 8) | 0x40);
if (Unknown1c >= 1)
{
Size += ((((Unknown18 + Unknown14 + Unknown10 + UnknownC + 1) * 16) + 0x658) * (Unknown1c + 1) + 0x13F) & ~0x3FL;
}
long WorkBufferSize = (Size + 0x1907D) & ~0xFFFL;
Context.ResponseData.Write(WorkBufferSize);
Context.Ns.Log.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{WorkBufferSize:x16}.");
return 0;
}
else
{
Context.ResponseData.Write(0L);
Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Library Revision 0x{RevMagic:x8} is not supported!");
return 0x499;
}
}
private static long RoundUp(long Value, int Size)
{
return (Value + (Size - 1)) & ~((long)Size - 1);
}
private static int NodeStatesGetWorkBufferSize(int Value)
{
int Result = (int)RoundUp(Value, 64);
if (Result < 0)
{
Result |= 7;
}
return 4 * (Value * Value) + 0x12 * Value + 2 * (Result / 8);
}
private static int EdgeMatrixGetWorkBufferSize(int Value)
{
int Result = (int)RoundUp(Value * Value, 64);
if (Result < 0)
{
Result |= 7;
}
return Result / 8;
}
public long GetAudioDevice(ServiceCtx Context)
{
long UserId = Context.RequestData.ReadInt64();
MakeObject(Context, new IAudioDevice());
return 0;
}
}
}