diff options
| author | Mary <me@thog.eu> | 2021-02-26 01:11:56 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-26 01:11:56 +0100 |
| commit | f556c80d0230056335632b60c71f1567e177239e (patch) | |
| tree | 748aa6be62b93a8e941e25dbd83f39e1dbb37035 /Ryujinx.HLE/HOS/Services/Audio/AudioOut | |
| parent | 1c49089ff00fc87dc4872f135dc6a0d36169a970 (diff) | |
Haydn: Part 1 (#2007)
* Haydn: Part 1
Based on my reverse of audio 11.0.0.
As always, core implementation under LGPLv3 for the same reasons as for Amadeus.
This place the bases of a more flexible audio system while making audout & audin accurate.
This have the following improvements:
- Complete reimplementation of audout and audin.
- Audin currently only have a dummy backend.
- Dramatically reduce CPU usage by up to 50% in common cases (SoundIO and OpenAL).
- Audio Renderer now can output to 5.1 devices when supported.
- Audio Renderer init its backend on demand instead of keeping two up all the time.
- All backends implementation are now in their own project.
- Ryujinx.Audio.Renderer was renamed Ryujinx.Audio and was refactored because of this.
As a note, games having issues with OpenAL haven't improved and will not
because of OpenAL design (stopping when buffers finish playing causing
possible audio "pops" when buffers are very small).
* Update for latest hexkyz's edits on Switchbrew
* audren: Rollback channel configuration changes
* Address gdkchan's comments
* Fix typo in OpenAL backend driver
* Address last comments
* Fix a nit
* Address gdkchan's comments
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Audio/AudioOut')
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs | 108 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs | 190 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs | 33 |
3 files changed, 331 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs new file mode 100644 index 00000000..f2588452 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOut.cs @@ -0,0 +1,108 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Integration; +using Ryujinx.Audio.Output; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer; +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut +{ + class AudioOut : IAudioOut + { + private AudioOutputSystem _system; + private uint _processHandle; + private KernelContext _kernelContext; + + public AudioOut(AudioOutputSystem system, KernelContext kernelContext, uint processHandle) + { + _system = system; + _kernelContext = kernelContext; + _processHandle = processHandle; + } + + public ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer) + { + return (ResultCode)_system.AppendBuffer(bufferTag, ref buffer); + } + + public bool ContainsBuffer(ulong bufferTag) + { + return _system.ContainsBuffer(bufferTag); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _system.Dispose(); + + _kernelContext.Syscall.CloseHandle((int)_processHandle); + } + } + + public bool FlushBuffers() + { + return _system.FlushBuffers(); + } + + public uint GetBufferCount() + { + return _system.GetBufferCount(); + } + + public ulong GetPlayedSampleCount() + { + return _system.GetPlayedSampleCount(); + } + + public ResultCode GetReleasedBuffers(Span<ulong> releasedBuffers, out uint releasedCount) + { + return (ResultCode)_system.GetReleasedBuffer(releasedBuffers, out releasedCount); + } + + public AudioDeviceState GetState() + { + return _system.GetState(); + } + + public float GetVolume() + { + return _system.GetVolume(); + } + + public KEvent RegisterBufferEvent() + { + IWritableEvent outEvent = _system.RegisterBufferEvent(); + + if (outEvent is AudioKernelEvent) + { + return ((AudioKernelEvent)outEvent).Event; + } + else + { + throw new NotImplementedException(); + } + } + + public void SetVolume(float volume) + { + _system.SetVolume(volume); + } + + public ResultCode Start() + { + return (ResultCode)_system.Start(); + } + + public ResultCode Stop() + { + return (ResultCode)_system.Stop(); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs new file mode 100644 index 00000000..4242eb7e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs @@ -0,0 +1,190 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Cpu; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Memory; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut +{ + class AudioOutServer : IpcService, IDisposable + { + private IAudioOut _impl; + + public AudioOutServer(IAudioOut impl) + { + _impl = impl; + } + + [Command(0)] + // GetAudioOutState() -> u32 state + public ResultCode GetAudioOutState(ServiceCtx context) + { + context.ResponseData.Write((uint)_impl.GetState()); + + return ResultCode.Success; + } + + [Command(1)] + // Start() + public ResultCode Start(ServiceCtx context) + { + return _impl.Start(); + } + + [Command(2)] + // Stop() + public ResultCode Stop(ServiceCtx context) + { + return _impl.Stop(); + } + + [Command(3)] + // AppendAudioOutBuffer(u64 bufferTag, buffer<nn::audio::AudioOutBuffer, 5> buffer) + public ResultCode AppendAudioOutBuffer(ServiceCtx context) + { + long position = context.Request.SendBuff[0].Position; + + ulong bufferTag = context.RequestData.ReadUInt64(); + + AudioUserBuffer data = MemoryHelper.Read<AudioUserBuffer>(context.Memory, position); + + return _impl.AppendBuffer(bufferTag, ref data); + } + + [Command(4)] + // RegisterBufferEvent() -> handle<copy> + public ResultCode RegisterBufferEvent(ServiceCtx context) + { + KEvent bufferEvent = _impl.RegisterBufferEvent(); + + if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + [Command(5)] + // GetReleasedAudioOutBuffers() -> (u32 count, buffer<u64, 6> tags) + public ResultCode GetReleasedAudioOutBuffers(ServiceCtx context) + { + long position = context.Request.ReceiveBuff[0].Position; + long size = context.Request.ReceiveBuff[0].Size; + + using (WritableRegion outputRegion = context.Memory.GetWritableRegion((ulong)position, (int)size)) + { + ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast<byte, ulong>(outputRegion.Memory.Span), out uint releasedCount); + + context.ResponseData.Write(releasedCount); + + return result; + } + } + + [Command(6)] + // ContainsAudioOutBuffer(u64 tag) -> b8 + public ResultCode ContainsAudioOutBuffer(ServiceCtx context) + { + ulong bufferTag = context.RequestData.ReadUInt64(); + + context.ResponseData.Write(_impl.ContainsBuffer(bufferTag)); + + return ResultCode.Success; + } + + [Command(7)] // 3.0.0+ + // AppendAudioOutBufferAuto(u64 tag, buffer<nn::audio::AudioOutBuffer, 0x21>) + public ResultCode AppendAudioOutBufferAuto(ServiceCtx context) + { + (long position, _) = context.Request.GetBufferType0x21(); + + ulong bufferTag = context.RequestData.ReadUInt64(); + + AudioUserBuffer data = MemoryHelper.Read<AudioUserBuffer>(context.Memory, position); + + return _impl.AppendBuffer(bufferTag, ref data); + } + + [Command(8)] // 3.0.0+ + // GetReleasedAudioOutBuffersAuto() -> (u32 count, buffer<u64, 0x22> tags) + public ResultCode GetReleasedAudioOutBuffersAuto(ServiceCtx context) + { + (long position, long size) = context.Request.GetBufferType0x22(); + + using (WritableRegion outputRegion = context.Memory.GetWritableRegion((ulong)position, (int)size)) + { + ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast<byte, ulong>(outputRegion.Memory.Span), out uint releasedCount); + + context.ResponseData.Write(releasedCount); + + return result; + } + } + + [Command(9)] // 4.0.0+ + // GetAudioOutBufferCount() -> u32 + public ResultCode GetAudioOutBufferCount(ServiceCtx context) + { + context.ResponseData.Write(_impl.GetBufferCount()); + + return ResultCode.Success; + } + + [Command(10)] // 4.0.0+ + // GetAudioOutPlayedSampleCount() -> u64 + public ResultCode GetAudioOutPlayedSampleCount(ServiceCtx context) + { + context.ResponseData.Write(_impl.GetPlayedSampleCount()); + + return ResultCode.Success; + } + + [Command(11)] // 4.0.0+ + // FlushAudioOutBuffers() -> b8 + public ResultCode FlushAudioOutBuffers(ServiceCtx context) + { + context.ResponseData.Write(_impl.FlushBuffers()); + + return ResultCode.Success; + } + + [Command(12)] // 6.0.0+ + // SetAudioOutVolume(s32) + public ResultCode SetAudioOutVolume(ServiceCtx context) + { + float volume = context.RequestData.ReadSingle(); + + _impl.SetVolume(volume); + + return ResultCode.Success; + } + + [Command(13)] // 6.0.0+ + // GetAudioOutVolume() -> s32 + public ResultCode GetAudioOutVolume(ServiceCtx context) + { + context.ResponseData.Write(_impl.GetVolume()); + + return ResultCode.Success; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _impl.Dispose(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs new file mode 100644 index 00000000..8533d3c5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/IAudioOut.cs @@ -0,0 +1,33 @@ +using Ryujinx.Audio.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut +{ + interface IAudioOut : IDisposable + { + AudioDeviceState GetState(); + + ResultCode Start(); + + ResultCode Stop(); + + ResultCode AppendBuffer(ulong bufferTag, ref AudioUserBuffer buffer); + + KEvent RegisterBufferEvent(); + + ResultCode GetReleasedBuffers(Span<ulong> releasedBuffers, out uint releasedCount); + + bool ContainsBuffer(ulong bufferTag); + + uint GetBufferCount(); + + ulong GetPlayedSampleCount(); + + bool FlushBuffers(); + + void SetVolume(float volume); + + float GetVolume(); + } +} |
