[APU] Fix mission-audio silence: ALSA underrun keepalive + guest_audio_flags
Two Linux mission-audio fixes for Project Sylpheed (audio played in intro/menu but died when a mission finished loading, never returning): - alsa_audio_driver: when the guest stalls (mission "Preparing for Sortie" load) and the ring buffer empties, feed silence to keep the PCM alive instead of sleeping. Previously the small buffer drained, XRUN'd, and playback never recovered (matches the known "audio muted permanently"). - xconfig: make the guest speaker config a cvar (guest_audio_flags, default Digital Stereo) instead of hardcoded Dolby Digital surround. (The practical fix on this box also needed log_mask=13 to stop kernel log spam starving the audio pipeline during missions — config, not code.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <ranges>
|
||||
|
||||
// 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<uint32_t>(XLanguage::kEnglish);
|
||||
xconfig_data_.user.country =
|
||||
static_cast<uint8_t>(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();
|
||||
|
||||
Reference in New Issue
Block a user