diff options
| author | mpnico <mpnico@gmail.com> | 2021-09-11 22:08:25 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-11 22:08:25 +0200 |
| commit | 117e32a6fffc30cdb895aa98483af7df353a8dd1 (patch) | |
| tree | 3a6ad3b396bbf641663dada2419709837f7c8268 /Ryujinx.Audio | |
| parent | b0e410a828fd37bf0d9021fc2f6b630e3944a861 (diff) | |
Implement a "Pause Emulation" option & hotkey (#2428)
* Add a "Pause Emulation" option and hotkey
Closes Ryujinx#1604
* Refactoring how pause is handled
* Applied suggested changes from review
* Applied suggested fixes
* Pass correct suspend type to threads for suspend/resume
* Fix NRE after stoping emulation
* Removing SimulateWakeUpMessage call after resuming emulation
* Skip suspending non game process
* Pause the tickCounter in the ExecutionContext
* Refactoring tickCounter pause/resume as suggested
* Fix Config migration to add pause hotkey
* Fixed pausing only application threads
* Fix exiting emulator while paused
* Avoid pause/resume while already paused/resumed
* Cleanup unused code
* Avoid restarting audio if stopping emulation while in pause.
* Added suggested changes
* Fix ConfigurationState
Diffstat (limited to 'Ryujinx.Audio')
6 files changed, 40 insertions, 1 deletions
diff --git a/Ryujinx.Audio/AudioManager.cs b/Ryujinx.Audio/AudioManager.cs index ab25150a..84e5b4f7 100644 --- a/Ryujinx.Audio/AudioManager.cs +++ b/Ryujinx.Audio/AudioManager.cs @@ -45,6 +45,8 @@ namespace Ryujinx.Audio /// </summary> private Thread _workerThread; + private bool _isRunning; + /// <summary> /// Create a new <see cref="AudioManager"/>. /// </summary> @@ -52,6 +54,7 @@ namespace Ryujinx.Audio { _updateRequiredEvents = new ManualResetEvent[2]; _actions = new Action[2]; + _isRunning = false; // Termination event. _updateRequiredEvents[1] = new ManualResetEvent(false); @@ -72,6 +75,7 @@ namespace Ryujinx.Audio throw new InvalidOperationException(); } + _isRunning = true; _workerThread.Start(); } @@ -96,7 +100,7 @@ namespace Ryujinx.Audio /// </summary> private void Update() { - while (true) + while (_isRunning) { int index = WaitHandle.WaitAny(_updateRequiredEvents); @@ -118,6 +122,14 @@ namespace Ryujinx.Audio } } + /// <summary> + /// Stop updating the <see cref="AudioManager"/> without stopping the worker thread. + /// </summary> + public void StopUpdates() + { + _isRunning = false; + } + public void Dispose() { Dispose(true); diff --git a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs index c0305f8a..0ae6a620 100644 --- a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs +++ b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs @@ -47,6 +47,11 @@ namespace Ryujinx.Audio.Backends.CompatLayer return _realDriver.GetUpdateRequiredEvent(); } + public ManualResetEvent GetPauseEvent() + { + return _realDriver.GetPauseEvent(); + } + private uint SelectHardwareChannelCount(uint targetChannelCount) { if (_realDriver.SupportsChannelCount(targetChannelCount)) diff --git a/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs b/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs index f24b359c..d729d3f6 100644 --- a/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs +++ b/Ryujinx.Audio/Backends/Dummy/DummyHardwareDeviceDriver.cs @@ -27,10 +27,12 @@ namespace Ryujinx.Audio.Backends.Dummy public class DummyHardwareDeviceDriver : IHardwareDeviceDriver { private ManualResetEvent _updateRequiredEvent; + private ManualResetEvent _pauseEvent; public DummyHardwareDeviceDriver() { _updateRequiredEvent = new ManualResetEvent(false); + _pauseEvent = new ManualResetEvent(true); } public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount) @@ -60,6 +62,11 @@ namespace Ryujinx.Audio.Backends.Dummy return _updateRequiredEvent; } + public ManualResetEvent GetPauseEvent() + { + return _pauseEvent; + } + public void Dispose() { Dispose(true); @@ -70,6 +77,7 @@ namespace Ryujinx.Audio.Backends.Dummy if (disposing) { // NOTE: The _updateRequiredEvent will be disposed somewhere else. + _pauseEvent.Dispose(); } } diff --git a/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs b/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs index 70738c90..1a53fa9b 100644 --- a/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs +++ b/Ryujinx.Audio/Integration/IHardwareDeviceDriver.cs @@ -36,6 +36,7 @@ namespace Ryujinx.Audio.Integration IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount); ManualResetEvent GetUpdateRequiredEvent(); + ManualResetEvent GetPauseEvent(); bool SupportsDirection(Direction direction); bool SupportsSampleRate(uint sampleRate); diff --git a/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs b/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs index ea975056..e15165b9 100644 --- a/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs +++ b/Ryujinx.Audio/Renderer/Dsp/AudioProcessor.cs @@ -55,6 +55,8 @@ namespace Ryujinx.Audio.Renderer.Dsp private long _playbackEnds; private ManualResetEvent _event; + private ManualResetEvent _pauseEvent; + public AudioProcessor() { _event = new ManualResetEvent(false); @@ -94,6 +96,7 @@ namespace Ryujinx.Audio.Renderer.Dsp _sessionCommandList = new RendererSession[Constants.AudioRendererSessionCountMax]; _event.Reset(); _lastTime = PerformanceCounter.ElapsedNanoseconds; + _pauseEvent = deviceDriver.GetPauseEvent(); StartThread(); @@ -202,6 +205,8 @@ namespace Ryujinx.Audio.Renderer.Dsp while (true) { + _pauseEvent?.WaitOne(); + MailboxMessage message = _mailbox.ReceiveMessage(); if (message == MailboxMessage.Stop) diff --git a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs index 71d0f318..f471a2e7 100644 --- a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs +++ b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs @@ -215,6 +215,14 @@ namespace Ryujinx.Audio.Renderer.Server } /// <summary> + /// Stop sending commands to the <see cref="AudioProcessor"/> without stopping the worker thread. + /// </summary> + public void StopSendingCommands() + { + _isRunning = false; + } + + /// <summary> /// Worker main function. This is used to dispatch audio renderer commands to the <see cref="AudioProcessor"/>. /// </summary> private void SendCommands() |
