Rename Ryujinx.Core to Ryujinx.HLE and add a separate project for a future LLE implementation
This commit is contained in:
14
Ryujinx.HLE/OsHle/Services/Aud/AudioOutData.cs
Normal file
14
Ryujinx.HLE/OsHle/Services/Aud/AudioOutData.cs
Normal 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;
|
||||
}
|
||||
}
|
222
Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs
Normal file
222
Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
154
Ryujinx.HLE/OsHle/Services/Aud/IAudioOut.cs
Normal file
154
Ryujinx.HLE/OsHle/Services/Aud/IAudioOut.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
115
Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs
Normal file
115
Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
92
Ryujinx.HLE/OsHle/Services/Aud/IAudioRenderer.cs
Normal file
92
Ryujinx.HLE/OsHle/Services/Aud/IAudioRenderer.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
135
Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs
Normal file
135
Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user