From 68220f6711a951689036f53883d2c2f6c91dcaee Mon Sep 17 00:00:00 2001 From: bookmist Date: Sat, 7 Feb 2026 16:20:29 +0300 Subject: [PATCH] audio: Rewrite SDL backend to use condvar wait modules/SceAudio: fix crackling audio, if empty buffer is used too often Co-authored-by: eagleflo --- vita3k/app/src/app_init.cpp | 9 +---- vita3k/audio/CMakeLists.txt | 3 +- vita3k/audio/include/audio/impl/cubeb_audio.h | 2 +- vita3k/audio/include/audio/impl/sdl_audio.h | 13 +++--- vita3k/audio/include/audio/state.h | 9 ++--- vita3k/audio/src/audio.cpp | 13 ++---- vita3k/audio/src/impl/cubeb_audio.cpp | 8 +--- vita3k/audio/src/impl/sdl_audio.cpp | 40 ++++++++----------- vita3k/modules/SceAudio/SceAudio.cpp | 13 +++++- 9 files changed, 44 insertions(+), 66 deletions(-) diff --git a/vita3k/app/src/app_init.cpp b/vita3k/app/src/app_init.cpp index c893e5d87..31d25ab41 100644 --- a/vita3k/app/src/app_init.cpp +++ b/vita3k/app/src/app_init.cpp @@ -425,14 +425,7 @@ bool late_init(EmuEnvState &state) { return false; } - const ResumeAudioThread resume_thread = [&state](SceUID thread_id) { - const auto thread = state.kernel.get_thread(thread_id); - const std::lock_guard lock(thread->mutex); - if (thread->status == ThreadStatus::wait) { - thread->update_status(ThreadStatus::run); - } - }; - if (!state.audio.init(resume_thread, state.cfg.audio_backend)) { + if (!state.audio.init(state.cfg.audio_backend)) { LOG_WARN("Failed to initialize audio! Audio will not work."); } diff --git a/vita3k/audio/CMakeLists.txt b/vita3k/audio/CMakeLists.txt index d40563aef..87e909cda 100644 --- a/vita3k/audio/CMakeLists.txt +++ b/vita3k/audio/CMakeLists.txt @@ -6,5 +6,4 @@ add_library( src/impl/cubeb_audio.cpp) target_include_directories(audio PUBLIC include) -target_link_libraries(audio PUBLIC SDL3::SDL3) -target_link_libraries(audio PRIVATE util cubeb kernel) +target_link_libraries(audio PRIVATE util cubeb SDL3::SDL3) diff --git a/vita3k/audio/include/audio/impl/cubeb_audio.h b/vita3k/audio/include/audio/impl/cubeb_audio.h index fda13f419..e4bf06a4c 100644 --- a/vita3k/audio/include/audio/impl/cubeb_audio.h +++ b/vita3k/audio/include/audio/impl/cubeb_audio.h @@ -53,7 +53,7 @@ public: bool init() override; AudioOutPortPtr open_port(int nb_channels, int freq, int nb_sample) override; - void audio_output(ThreadState &thread, AudioOutPort &out_port, const void *buffer) override; + void audio_output(AudioOutPort &out_port, const void *buffer) override; void set_volume(AudioOutPort &out_port, float volume) override; void switch_state(const bool pause) override; }; diff --git a/vita3k/audio/include/audio/impl/sdl_audio.h b/vita3k/audio/include/audio/impl/sdl_audio.h index 193e20c2b..efef71ea1 100644 --- a/vita3k/audio/include/audio/impl/sdl_audio.h +++ b/vita3k/audio/include/audio/impl/sdl_audio.h @@ -18,36 +18,37 @@ #pragma once #include "../state.h" - #include +#include class SDLAudioAdapter : public AudioAdapter { private: SDL_AudioDeviceID device_id = 0; int device_buffer_samples = 0; SDL_AudioSpec dst_spec; + static void SDLCALL thread_wakeup_callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount); public: - SDLAudioAdapter(AudioState &audio_state); + explicit SDLAudioAdapter(AudioState &audio_state); ~SDLAudioAdapter() override; bool init() override; void switch_state(const bool pause) override; AudioOutPortPtr open_port(int nb_channels, int freq, int nb_sample) override; - void audio_output(ThreadState &thread, AudioOutPort &out_port, const void *buffer) override; + void audio_output(AudioOutPort &out_port, const void *buffer) override; void set_volume(AudioOutPort &out_port, float volume) override; int get_rest_sample(AudioOutPort &out_port) override; }; -typedef std::shared_ptr AudioStreamPtr; +using AudioStreamPtr = std::shared_ptr; struct SDLAudioOutPort : public AudioOutPort { - // thread currently waiting for the audio to be processed - SceUID thread = -1; int channels = 2; AudioStreamPtr stream; SDLAudioAdapter &adapter; + std::mutex mutex; + std::condition_variable cond_var; SDLAudioOutPort(AudioStreamPtr stream, AudioAdapter &adapter) : stream(std::move(stream)) , adapter(dynamic_cast(adapter)) {} diff --git a/vita3k/audio/include/audio/state.h b/vita3k/audio/include/audio/state.h index d6ab5509a..b1aa2519b 100644 --- a/vita3k/audio/include/audio/state.h +++ b/vita3k/audio/include/audio/state.h @@ -28,8 +28,6 @@ #define SCE_AUDIO_OUT_MAX_VOL 32768 //!< Maximum output port volume #define SCE_AUDIO_VOLUME_0DB SCE_AUDIO_OUT_MAX_VOL //!< Maximum output port volume -typedef std::function ResumeAudioThread; - struct AudioOutPort { // Channel range from 0 - 32768 int left_channel_volume = SCE_AUDIO_VOLUME_0DB; @@ -73,7 +71,7 @@ public: virtual bool init() = 0; virtual AudioOutPortPtr open_port(int nb_channels, int freq, int nb_sample) { return nullptr; } - virtual void audio_output(ThreadState &thread, AudioOutPort &out_port, const void *buffer) {} + virtual void audio_output(AudioOutPort &out_port, const void *buffer) {} virtual void set_volume(AudioOutPort &out_port, float volume) {} virtual void switch_state(const bool pause) {} virtual int get_rest_sample(AudioOutPort &out_port) { return 0; }; @@ -87,14 +85,13 @@ struct AudioState { int next_port_id = 1; AudioOutPortPtrs out_ports; AudioInPort in_port; - ResumeAudioThread resume_thread; std::string audio_backend; float global_volume = 1; - bool init(const ResumeAudioThread &resume_thread, const std::string &adapter_name); + bool init(const std::string &adapter_name); void set_backend(const std::string &adapter_name); AudioOutPortPtr open_port(int nb_channels, int freq, int nb_sample); - void audio_output(ThreadState &thread, AudioOutPort &out_port, const void *buffer); + void audio_output(AudioOutPort &out_port, const void *buffer); void set_volume(AudioOutPort &out_port, float volume); void set_global_volume(float volume); void switch_state(const bool pause); diff --git a/vita3k/audio/src/audio.cpp b/vita3k/audio/src/audio.cpp index ca51a2a98..f99445810 100644 --- a/vita3k/audio/src/audio.cpp +++ b/vita3k/audio/src/audio.cpp @@ -20,17 +20,12 @@ #include