diff --git a/plugins/spu2-x/src/Linux/Config.cpp b/plugins/spu2-x/src/Linux/Config.cpp index a61df22fb..87d470247 100644 --- a/plugins/spu2-x/src/Linux/Config.cpp +++ b/plugins/spu2-x/src/Linux/Config.cpp @@ -19,6 +19,9 @@ #include "Dialogs.h" #include "Config.h" +#include +#include + #ifdef PCSX2_DEVBUILD static const int LATENCY_MAX = 3000; #else @@ -70,6 +73,7 @@ u32 OutputModule = 0; int SndOutLatencyMS = 300; int SynchMode = 0; // Time Stretch, Async or Disabled static u32 OutputAPI = 0; +static u32 SdlOutputAPI = 0; int numSpeakers = 0; int dplLevel = 0; @@ -121,10 +125,21 @@ void ReadSettings() if (temp == L"OSS") OutputAPI = 1; if (temp == L"JACK") OutputAPI = 2; + CfgReadStr( L"SDL", L"HostApi", temp, L"pulseaudio" ); + SdlOutputAPI = -1; +#if SDL_MAJOR_VERSION >= 2 + // YES It sucks ... + for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + if (!temp.Cmp(wxString(SDL_GetAudioDriver(i), wxConvUTF8))) + SdlOutputAPI = i; + } +#endif + SndOutLatencyMS = CfgReadInt(L"OUTPUT",L"Latency", 300); SynchMode = CfgReadInt( L"OUTPUT", L"Synch_Mode", 0); PortaudioOut->ReadSettings(); + SDLOut->ReadSettings(); SoundtouchCfg::ReadSettings(); DebugConfig::ReadSettings(); @@ -167,6 +182,7 @@ void WriteSettings() CfgWriteInt(L"OUTPUT",L"Synch_Mode", SynchMode); PortaudioOut->WriteSettings(); + SDLOut->WriteSettings(); SoundtouchCfg::WriteSettings(); DebugConfig::WriteSettings(); } @@ -198,6 +214,9 @@ void DisplayDialog() GtkWidget *output_frame, *output_box; GtkWidget *mod_label, *mod_box; GtkWidget *api_label, *api_box; +#if SDL_MAJOR_VERSION >= 2 + GtkWidget *sdl_api_label, *sdl_api_box; +#endif GtkWidget *latency_label, *latency_slide; GtkWidget *sync_label, *sync_box; GtkWidget *advanced_button; @@ -242,6 +261,16 @@ void DisplayDialog() gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "2 - JACK"); gtk_combo_box_set_active(GTK_COMBO_BOX(api_box), OutputAPI); +#if SDL_MAJOR_VERSION >= 2 + sdl_api_label = gtk_label_new ("SDL API:"); + sdl_api_box = gtk_combo_box_text_new (); + // YES It sucks ... + for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sdl_api_box), SDL_GetAudioDriver(i)); + } + gtk_combo_box_set_active(GTK_COMBO_BOX(sdl_api_box), SdlOutputAPI); +#endif + latency_label = gtk_label_new ("Latency:"); #if GTK_MAJOR_VERSION < 3 latency_slide = gtk_hscale_new_with_range(LATENCY_MIN, LATENCY_MAX, 5); @@ -282,6 +311,10 @@ void DisplayDialog() gtk_container_add(GTK_CONTAINER(output_box), mod_box); gtk_container_add(GTK_CONTAINER(output_box), api_label); gtk_container_add(GTK_CONTAINER(output_box), api_box); +#if SDL_MAJOR_VERSION >= 2 + gtk_container_add(GTK_CONTAINER(output_box), sdl_api_label); + gtk_container_add(GTK_CONTAINER(output_box), sdl_api_box); +#endif gtk_container_add(GTK_CONTAINER(output_box), sync_label); gtk_container_add(GTK_CONTAINER(output_box), sync_box); gtk_container_add(GTK_CONTAINER(output_box), latency_label); @@ -327,6 +360,14 @@ void DisplayDialog() } } +#if SDL_MAJOR_VERSION >= 2 + if (gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box)) != -1) { + SdlOutputAPI = gtk_combo_box_get_active(GTK_COMBO_BOX(sdl_api_box)); + // YES It sucks ... + SDLOut->SetApiSettings(wxString(SDL_GetAudioDriver(SdlOutputAPI), wxConvUTF8)); + } +#endif + SndOutLatencyMS = gtk_range_get_value(GTK_RANGE(latency_slide)); if (gtk_combo_box_get_active(GTK_COMBO_BOX(sync_box)) != -1) diff --git a/plugins/spu2-x/src/SndOut_SDL.cpp b/plugins/spu2-x/src/SndOut_SDL.cpp index 4e3c63dad..246d192e1 100644 --- a/plugins/spu2-x/src/SndOut_SDL.cpp +++ b/plugins/spu2-x/src/SndOut_SDL.cpp @@ -18,6 +18,7 @@ #include "Global.h" #include "SndOut.h" +#include "Dialogs.h" #include @@ -26,11 +27,7 @@ * build wx without sdl support, though) and onepad at the time of writing this. */ #include #include -#if SDL_MAJOR_VERSION >= 2 -typedef StereoOut32 StereoOut_SDL; -#else typedef StereoOut16 StereoOut_SDL; -#endif namespace { /* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound @@ -41,12 +38,7 @@ namespace { * sample count and SDL may provide otherwise. Pulseaudio will cut this value in half if * PA_STREAM_ADJUST_LATENCY is set in the backened, for example. */ const Uint16 desiredSamples = 1024; - const Uint16 format = -#if SDL_MAJOR_VERSION >= 2 - AUDIO_S32SYS; -#else - AUDIO_S16SYS; -#endif + const Uint16 format = AUDIO_S16SYS; Uint16 samples = desiredSamples; @@ -67,16 +59,46 @@ namespace { struct SDLAudioMod : public SndOutModule { static SDLAudioMod mod; + std::string m_api; s32 Init() { + ReadSettings(); + +#if SDL_MAJOR_VERSION >= 2 + std::cerr << "Request SDL audio driver: " << m_api.c_str() << std::endl; +#endif + /* SDL backends will mangle the AudioSpec and change the sample count. If we reopen * the audio backend, we need to make sure we keep our desired samples in the spec */ spec.samples = desiredSamples; - if(SDL_Init(SDL_INIT_AUDIO) < 0 || SDL_OpenAudio(&spec, NULL) < 0) { + // Mandatory otherwise, init will be redone in SDL_OpenAudio + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + std::cerr << "SPU2-X: SDL INIT audio error: " << SDL_GetError() << std::endl; + return -1; + } + +#if SDL_MAJOR_VERSION >= 2 + if (m_api.compare("pulseaudio")) { + // Close the audio, but keep the subsystem open + SDL_AudioQuit(); + // Reopen the audio + if (SDL_AudioInit(m_api.c_str()) < 0) { + std::cerr << "SPU2-X: SDL audio init error: " << SDL_GetError() << std::endl; + return -1; + } + } +#endif + + if (SDL_OpenAudio(&spec, NULL) < 0) { std::cerr << "SPU2-X: SDL audio error: " << SDL_GetError() << std::endl; return -1; } + +#if SDL_MAJOR_VERSION >= 2 + std::cerr << "Opened SDL audio driver: " << SDL_GetCurrentAudioDriver() << std::endl; +#endif + /* This is so ugly. It is hilariously ugly. I didn't use a vector to save reallocs. */ if(samples != spec.samples || buffer == NULL) buffer = std::unique_ptr(new StereoOut_SDL[spec.samples]); @@ -93,23 +115,51 @@ struct SDLAudioMod : public SndOutModule { const wchar_t* GetLongName() const { return L"SDL Audio"; } void Close() { - SDL_CloseAudio(); + // Related to SDL_Init(SDL_INIT_AUDIO) + SDL_QuitSubSystem(SDL_INIT_AUDIO); } + ~SDLAudioMod() { Close(); } + s32 Test() const { return 0; } - void Configure(uptr parent) {} - void ReadSettings() {} - void SetApiSettings(wxString api) {} - void WriteSettings() const {}; int GetEmptySampleCount() { return 0; } - ~SDLAudioMod() { Close(); } + void Configure(uptr parent) {} + + void ReadSettings() { + wxString api(L"EMPTYEMPTYEMPTY"); + CfgReadStr(L"SDL", L"HostApi", api, L"pulseaudio"); + SetApiSettings(api); + } + + void WriteSettings() const { + CfgWriteStr(L"SDL", L"HostApi", wxString(m_api.c_str(), wxConvUTF8)); + }; + + void SetApiSettings(wxString api) { +#if SDL_MAJOR_VERSION >= 2 + // Validate the api name + bool valid = false; + std::string api_name = std::string(api.utf8_str()); + for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + valid |= (api_name.compare(SDL_GetAudioDriver(i)) == 0); + } + if (valid) { + m_api = api.utf8_str(); + } else { + std::cerr << "SDL audio driver configuration is invalid!" << std::endl + << "It will be replaced by pulseaudio!" << std::endl; + m_api = "pulseaudio"; + } +#endif + } + private: SDL_AudioSpec spec; - SDLAudioMod() - : spec({SampleRate, format, channels, 0, + SDLAudioMod() : m_api("pulseaudio"), + spec({SampleRate, format, channels, 0, desiredSamples, 0, 0, &callback_fillBuffer, nullptr}) { // Number of samples must be a multiple of packet size.