diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index aaf10a7cf9..c07f7181f1 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -168,6 +168,7 @@ elseif(WIN32) else() set(PLATFORM_ARCH "linux/x86_64") option(USE_ALSA "ALSA audio backend" ON) + option(USE_PULSE "PulseAudio audio backend" ON) option(USE_LIBEVDEV "libevdev-based joystick support" ON) endif() @@ -180,6 +181,15 @@ if(USE_ALSA) list(APPEND ADDITIONAL_LIBS ${ALSA_LDFLAGS}) endif() endif() +if(USE_PULSE) + find_package(PkgConfig) + pkg_check_modules(PULSE libpulse-simple) + if(PULSE_FOUND) + add_definitions(-DHAVE_PULSE) + include_directories(SYSTEM ${PULSE_INCLUDE_DIRS}) + list(APPEND ADDITIONAL_LIBS ${PULSE_LDFLAGS}) + endif() +endif() if(USE_LIBEVDEV) find_package(PkgConfig) pkg_check_modules(LIBEVDEV libevdev) diff --git a/rpcs3/Emu/Audio/Pulse/PulseThread.cpp b/rpcs3/Emu/Audio/Pulse/PulseThread.cpp new file mode 100644 index 0000000000..83109a0ccb --- /dev/null +++ b/rpcs3/Emu/Audio/Pulse/PulseThread.cpp @@ -0,0 +1,60 @@ +#include "Emu/System.h" +#include "PulseThread.h" + +#ifdef HAVE_PULSE + +#include +#include + +PulseThread::PulseThread() +{ +} + +PulseThread::~PulseThread() +{ + this->Close(); +} + +void PulseThread::Play() +{ +} + +void PulseThread::Close() +{ + if(this->connection) { + pa_simple_free(this->connection); + this->connection = nullptr; + } +} + +void PulseThread::Stop() +{ +} + +void PulseThread::Open(const void* src, int size) +{ + pa_sample_spec ss; + ss.format = g_cfg.audio.convert_to_u16 ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE; + ss.channels = g_cfg.audio.downmix_to_2ch ? 2 : 8; + ss.rate = 48000; + + int err; + this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, NULL, NULL, &err); + if(!this->connection) { + fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err)); + } + + this->AddData(src, size); +} + +void PulseThread::AddData(const void* src, int size) +{ + if(this->connection) { + int err; + if(pa_simple_write(this->connection, src, size, &err) < 0) { + fprintf(stderr, "PulseAusio: Failed to write audio stream: %s\n", pa_strerror(err)); + } + } +} + +#endif diff --git a/rpcs3/Emu/Audio/Pulse/PulseThread.h b/rpcs3/Emu/Audio/Pulse/PulseThread.h new file mode 100644 index 0000000000..657722f622 --- /dev/null +++ b/rpcs3/Emu/Audio/Pulse/PulseThread.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef HAVE_PULSE +#include +#include "Emu/Audio/AudioThread.h" + +class PulseThread : public AudioThread +{ +public: + PulseThread(); + virtual ~PulseThread() override; + + virtual void Play() override; + virtual void Open(const void* src, int size) override; + virtual void Close() override; + virtual void Stop() override; + virtual void AddData(const void* src, int size) override; + +private: + pa_simple *connection = nullptr; +}; + +#endif diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 08e35854f8..8b66a661ad 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -166,8 +166,12 @@ void fmt_class_string::format(std::string& out, u64 arg) case audio_renderer::null: return "Null"; #ifdef _WIN32 case audio_renderer::xaudio: return "XAudio2"; -#elif defined(HAVE_ALSA) +#endif +#ifdef HAVE_ALSA case audio_renderer::alsa: return "ALSA"; +#endif +#ifdef HAVE_PULSE + case audio_renderer::pulse: return "PulseAudio"; #endif case audio_renderer::openal: return "OpenAL"; } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 1f35dd6d6b..c6bb1ee76d 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -88,8 +88,12 @@ enum class audio_renderer null, #ifdef _WIN32 xaudio, -#elif defined(HAVE_ALSA) +#endif +#ifdef HAVE_ALSA alsa, +#endif +#ifdef HAVE_PULSE + pulse, #endif openal, }; diff --git a/rpcs3/rpcs3_app.cpp b/rpcs3/rpcs3_app.cpp index ac200a3758..2c62e7b08d 100644 --- a/rpcs3/rpcs3_app.cpp +++ b/rpcs3/rpcs3_app.cpp @@ -48,6 +48,9 @@ #ifdef HAVE_ALSA #include "Emu/Audio/ALSA/ALSAThread.h" #endif +#ifdef HAVE_PULSE +#include "Emu/Audio/Pulse/PulseThread.h" +#endif // For now, a trivial constructor/destructor. May add command line usage later. rpcs3_app::rpcs3_app(int& argc, char** argv) : QApplication(argc, argv) @@ -234,9 +237,14 @@ void rpcs3_app::InitializeCallbacks() case audio_renderer::null: return std::make_shared(); #ifdef _WIN32 case audio_renderer::xaudio: return std::make_shared(); -#elif defined(HAVE_ALSA) +#endif +#ifdef HAVE_ALSA case audio_renderer::alsa: return std::make_shared(); #endif +#ifdef HAVE_PULSE + case audio_renderer::pulse: return std::make_shared(); +#endif + case audio_renderer::openal: return std::make_shared(); default: fmt::throw_exception("Invalid audio renderer: %s" HERE, type); }