diff options
| -rw-r--r-- | src/audio_core/renderer/adsp/audio_renderer.cpp | 2 | ||||
| -rw-r--r-- | src/audio_core/renderer/adsp/audio_renderer.h | 1 | ||||
| -rw-r--r-- | src/audio_core/renderer/system_manager.cpp | 18 | ||||
| -rw-r--r-- | src/audio_core/renderer/system_manager.h | 7 | ||||
| -rw-r--r-- | src/audio_core/sink/sink_stream.cpp | 15 | ||||
| -rw-r--r-- | src/audio_core/sink/sink_stream.h | 9 |
6 files changed, 28 insertions, 24 deletions
diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 42b4b167a..503f40349 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp | |||
| @@ -189,6 +189,8 @@ void AudioRenderer::ThreadFunc() { | |||
| 189 | max_time = std::min(command_buffer.time_limit, max_time); | 189 | max_time = std::min(command_buffer.time_limit, max_time); |
| 190 | command_list_processor.SetProcessTimeMax(max_time); | 190 | command_list_processor.SetProcessTimeMax(max_time); |
| 191 | 191 | ||
| 192 | streams[index]->WaitFreeSpace(); | ||
| 193 | |||
| 192 | // Process the command list | 194 | // Process the command list |
| 193 | { | 195 | { |
| 194 | MICROPROFILE_SCOPE(Audio_Renderer); | 196 | MICROPROFILE_SCOPE(Audio_Renderer); |
diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h index 151f38c1b..f97f9401e 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.h +++ b/src/audio_core/renderer/adsp/audio_renderer.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/reader_writer_queue.h" | 13 | #include "common/reader_writer_queue.h" |
| 14 | #include "common/thread.h" | 14 | #include "common/thread.h" |
| 15 | #include "common/polyfill_thread.h" | ||
| 15 | 16 | ||
| 16 | namespace Core { | 17 | namespace Core { |
| 17 | namespace Timing { | 18 | namespace Timing { |
diff --git a/src/audio_core/renderer/system_manager.cpp b/src/audio_core/renderer/system_manager.cpp index 9ddfa4a91..07d8ed093 100644 --- a/src/audio_core/renderer/system_manager.cpp +++ b/src/audio_core/renderer/system_manager.cpp | |||
| @@ -17,11 +17,7 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager", | |||
| 17 | namespace AudioCore::AudioRenderer { | 17 | namespace AudioCore::AudioRenderer { |
| 18 | 18 | ||
| 19 | SystemManager::SystemManager(Core::System& core_) | 19 | SystemManager::SystemManager(Core::System& core_) |
| 20 | : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()}, | 20 | : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {} |
| 21 | thread_event{Core::Timing::CreateEvent( | ||
| 22 | "AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { | ||
| 23 | return ThreadFunc2(time); | ||
| 24 | })} {} | ||
| 25 | 21 | ||
| 26 | SystemManager::~SystemManager() { | 22 | SystemManager::~SystemManager() { |
| 27 | Stop(); | 23 | Stop(); |
| @@ -32,8 +28,6 @@ bool SystemManager::InitializeUnsafe() { | |||
| 32 | if (adsp.Start()) { | 28 | if (adsp.Start()) { |
| 33 | active = true; | 29 | active = true; |
| 34 | thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); | 30 | thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); |
| 35 | core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME, | ||
| 36 | thread_event); | ||
| 37 | } | 31 | } |
| 38 | } | 32 | } |
| 39 | 33 | ||
| @@ -44,7 +38,6 @@ void SystemManager::Stop() { | |||
| 44 | if (!active) { | 38 | if (!active) { |
| 45 | return; | 39 | return; |
| 46 | } | 40 | } |
| 47 | core.CoreTiming().UnscheduleEvent(thread_event, {}); | ||
| 48 | active = false; | 41 | active = false; |
| 49 | update.store(true); | 42 | update.store(true); |
| 50 | update.notify_all(); | 43 | update.notify_all(); |
| @@ -110,16 +103,7 @@ void SystemManager::ThreadFunc() { | |||
| 110 | 103 | ||
| 111 | adsp.Signal(); | 104 | adsp.Signal(); |
| 112 | adsp.Wait(); | 105 | adsp.Wait(); |
| 113 | |||
| 114 | update.wait(false); | ||
| 115 | update.store(false); | ||
| 116 | } | 106 | } |
| 117 | } | 107 | } |
| 118 | 108 | ||
| 119 | std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) { | ||
| 120 | update.store(true); | ||
| 121 | update.notify_all(); | ||
| 122 | return std::nullopt; | ||
| 123 | } | ||
| 124 | |||
| 125 | } // namespace AudioCore::AudioRenderer | 109 | } // namespace AudioCore::AudioRenderer |
diff --git a/src/audio_core/renderer/system_manager.h b/src/audio_core/renderer/system_manager.h index 415ddb74f..1f0bbd8b4 100644 --- a/src/audio_core/renderer/system_manager.h +++ b/src/audio_core/renderer/system_manager.h | |||
| @@ -68,11 +68,6 @@ private: | |||
| 68 | */ | 68 | */ |
| 69 | void ThreadFunc(); | 69 | void ThreadFunc(); |
| 70 | 70 | ||
| 71 | /** | ||
| 72 | * Signalling core timing thread to run ThreadFunc. | ||
| 73 | */ | ||
| 74 | std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time); | ||
| 75 | |||
| 76 | enum class StreamState { | 71 | enum class StreamState { |
| 77 | Filling, | 72 | Filling, |
| 78 | Steady, | 73 | Steady, |
| @@ -95,8 +90,6 @@ private: | |||
| 95 | ADSP::ADSP& adsp; | 90 | ADSP::ADSP& adsp; |
| 96 | /// AudioRenderer mailbox for communication | 91 | /// AudioRenderer mailbox for communication |
| 97 | ADSP::AudioRenderer_Mailbox* mailbox{}; | 92 | ADSP::AudioRenderer_Mailbox* mailbox{}; |
| 98 | /// Core timing event to signal main thread | ||
| 99 | std::shared_ptr<Core::Timing::EventType> thread_event; | ||
| 100 | /// Atomic for main thread to wait on | 93 | /// Atomic for main thread to wait on |
| 101 | std::atomic<bool> update{}; | 94 | std::atomic<bool> update{}; |
| 102 | }; | 95 | }; |
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 1af96f793..a54c61845 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp | |||
| @@ -205,6 +205,10 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz | |||
| 205 | // If we're paused or going to shut down, we don't want to consume buffers as coretiming is | 205 | // If we're paused or going to shut down, we don't want to consume buffers as coretiming is |
| 206 | // paused and we'll desync, so just play silence. | 206 | // paused and we'll desync, so just play silence. |
| 207 | if (system.IsPaused() || system.IsShuttingDown()) { | 207 | if (system.IsPaused() || system.IsShuttingDown()) { |
| 208 | if (system.IsShuttingDown()) { | ||
| 209 | release_cv.notify_one(); | ||
| 210 | } | ||
| 211 | |||
| 208 | static constexpr std::array<s16, 6> silence{}; | 212 | static constexpr std::array<s16, 6> silence{}; |
| 209 | for (size_t i = frames_written; i < num_frames; i++) { | 213 | for (size_t i = frames_written; i < num_frames; i++) { |
| 210 | std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes); | 214 | std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes); |
| @@ -240,6 +244,12 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz | |||
| 240 | } | 244 | } |
| 241 | // Successfully dequeued a new buffer. | 245 | // Successfully dequeued a new buffer. |
| 242 | queued_buffers--; | 246 | queued_buffers--; |
| 247 | |||
| 248 | { | ||
| 249 | std::unique_lock lk{release_mutex}; | ||
| 250 | } | ||
| 251 | |||
| 252 | release_cv.notify_one(); | ||
| 243 | } | 253 | } |
| 244 | 254 | ||
| 245 | // Get the minimum frames available between the currently playing buffer, and the | 255 | // Get the minimum frames available between the currently playing buffer, and the |
| @@ -303,4 +313,9 @@ u64 SinkStream::GetExpectedPlayedSampleCount() { | |||
| 303 | return std::min<u64>(exp_played_sample_count, max_played_sample_count); | 313 | return std::min<u64>(exp_played_sample_count, max_played_sample_count); |
| 304 | } | 314 | } |
| 305 | 315 | ||
| 316 | void SinkStream::WaitFreeSpace() { | ||
| 317 | std::unique_lock lk{release_mutex}; | ||
| 318 | release_cv.wait(lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); }); | ||
| 319 | } | ||
| 320 | |||
| 306 | } // namespace AudioCore::Sink | 321 | } // namespace AudioCore::Sink |
diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 2340c936c..709f3b0ec 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "common/reader_writer_queue.h" | 16 | #include "common/reader_writer_queue.h" |
| 17 | #include "common/ring_buffer.h" | 17 | #include "common/ring_buffer.h" |
| 18 | #include "common/thread.h" | 18 | #include "common/thread.h" |
| 19 | #include "common/polyfill_thread.h" | ||
| 19 | 20 | ||
| 20 | namespace Core { | 21 | namespace Core { |
| 21 | class System; | 22 | class System; |
| @@ -219,6 +220,11 @@ public: | |||
| 219 | */ | 220 | */ |
| 220 | u64 GetExpectedPlayedSampleCount(); | 221 | u64 GetExpectedPlayedSampleCount(); |
| 221 | 222 | ||
| 223 | /** | ||
| 224 | * Waits for free space in the sample ring buffer | ||
| 225 | */ | ||
| 226 | void WaitFreeSpace(); | ||
| 227 | |||
| 222 | protected: | 228 | protected: |
| 223 | /// Core system | 229 | /// Core system |
| 224 | Core::System& system; | 230 | Core::System& system; |
| @@ -258,6 +264,9 @@ private: | |||
| 258 | f32 system_volume{1.0f}; | 264 | f32 system_volume{1.0f}; |
| 259 | /// Set via IAudioDevice service calls | 265 | /// Set via IAudioDevice service calls |
| 260 | f32 device_volume{1.0f}; | 266 | f32 device_volume{1.0f}; |
| 267 | /// Signalled when ring buffer entries are consumed | ||
| 268 | std::condition_variable release_cv; | ||
| 269 | std::mutex release_mutex; | ||
| 261 | std::mutex stall_guard; | 270 | std::mutex stall_guard; |
| 262 | std::unique_lock<std::mutex> stalled_lock; | 271 | std::unique_lock<std::mutex> stalled_lock; |
| 263 | }; | 272 | }; |