diff --git a/src/xenia/apu/alsa/alsa_audio_driver.cc b/src/xenia/apu/alsa/alsa_audio_driver.cc index 700318fdf..a38477b9c 100644 --- a/src/xenia/apu/alsa/alsa_audio_driver.cc +++ b/src/xenia/apu/alsa/alsa_audio_driver.cc @@ -336,8 +336,30 @@ void ALSAAudioDriver::WorkerThread() { size_t current_write = write_index_.load(std::memory_order_acquire); if (current_read == current_write) { - // No data available, sleep and try again - std::this_thread::sleep_for(std::chrono::milliseconds(5)); + // No guest audio available. During long guest stalls (e.g. a mission + // "Preparing for Sortie" load) the game stops submitting frames; if we + // merely sleep, ALSA drains its small buffer, XRUNs, and playback never + // recovers (the game's audio is silent for the rest of the session). + // Keep the PCM alive by topping it up with silence whenever the queued + // audio runs low, so real audio resumes seamlessly once the stall ends. + snd_pcm_sframes_t avail = snd_pcm_avail_update(pcm_handle_); + if (avail < 0) { + if (!RecoverFromUnderrun(avail)) { + running_ = false; + } + continue; + } + snd_pcm_uframes_t queued = + (buffer_size_ > (snd_pcm_uframes_t)avail) ? buffer_size_ - avail : 0; + if (queued < period_size_ * 2) { + snd_pcm_sframes_t w = + snd_pcm_writei(pcm_handle_, silence.get(), period_size_); + if (w < 0) { + RecoverFromUnderrun(w); + } + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + } continue; } diff --git a/src/xenia/kernel/xconfig.cc b/src/xenia/kernel/xconfig.cc index 57cc50f95..344feba0f 100644 --- a/src/xenia/kernel/xconfig.cc +++ b/src/xenia/kernel/xconfig.cc @@ -9,6 +9,7 @@ #include "xenia/kernel/xconfig.h" +#include "xenia/base/cvar.h" #include "xenia/base/logging.h" #include "xenia/base/filesystem.h" @@ -19,6 +20,17 @@ #include +// Speaker configuration reported to the guest (XCONFIG_USER_AUDIO_FLAGS). +// Default = 0 (Digital Stereo): the Linux/ALSA APU driver's 5.1 (6-channel) +// path yields silence in some titles (e.g. Project Sylpheed missions), while +// stereo output works, so stereo is the safe default. Set to 0x00010001 for +// Dolby Digital + Pro Logic surround. +DEFINE_uint32(guest_audio_flags, 0, + "Speaker config reported to the guest (XCONFIG_USER_AUDIO_FLAGS): " + "0 = Digital Stereo (safe on Linux/ALSA), 0x00010001 = Dolby " + "Digital + Pro Logic surround.", + "APU"); + namespace xe { namespace kernel { @@ -94,7 +106,7 @@ void XConfig::SetDefaults() { xconfig_data_.user.language = static_cast(XLanguage::kEnglish); xconfig_data_.user.country = static_cast(XOnlineCountry::kUnitedStates); - xconfig_data_.user.audio_flags = DolbyDigital | DolbyProLogic; + xconfig_data_.user.audio_flags = cvars::guest_audio_flags; xconfig_data_.user.av_pack_hdmi_sz = XHDTVResolution.at(1).to_host(); xconfig_data_.user.av_pack_component_sz = XHDTVResolution.at(1).to_host(); xconfig_data_.user.av_pack_vga_sz = XVGAResolution.at(3).to_host();