mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-06 17:32:40 +00:00
audio: Handle SDL audio queue stalls.
This commit is contained in:
parent
cf4bd5446f
commit
3a02d2860c
@ -13,7 +13,8 @@ namespace Libraries::AudioOut {
|
|||||||
|
|
||||||
class SDLPortBackend : public PortBackend {
|
class SDLPortBackend : public PortBackend {
|
||||||
public:
|
public:
|
||||||
explicit SDLPortBackend(const PortOut& port) : buffer_size(port.buffer_size) {
|
explicit SDLPortBackend(const PortOut& port)
|
||||||
|
: frame_size(port.frame_size), buffer_size(port.buffer_size) {
|
||||||
// We want the latency for delivering frames out to be as small as possible,
|
// We want the latency for delivering frames out to be as small as possible,
|
||||||
// so set the sample frames hint to the number of frames per buffer.
|
// so set the sample frames hint to the number of frames per buffer.
|
||||||
const auto samples_num_str = std::to_string(port.buffer_frames);
|
const auto samples_num_str = std::to_string(port.buffer_frames);
|
||||||
@ -32,6 +33,7 @@ public:
|
|||||||
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
|
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
queue_threshold = CalculateQueueThreshold();
|
||||||
if (!SDL_ResumeAudioStreamDevice(stream)) {
|
if (!SDL_ResumeAudioStreamDevice(stream)) {
|
||||||
LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError());
|
LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError());
|
||||||
SDL_DestroyAudioStream(stream);
|
SDL_DestroyAudioStream(stream);
|
||||||
@ -52,6 +54,17 @@ public:
|
|||||||
if (!stream) {
|
if (!stream) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// AudioOut library manages timing, but we still need to guard against the SDL
|
||||||
|
// audio queue stalling, which may happen during device changes, for example.
|
||||||
|
// Otherwise, latency may grow over time unbounded.
|
||||||
|
if (const auto queued = SDL_GetAudioStreamQueued(stream); queued >= queue_threshold) {
|
||||||
|
LOG_WARNING(Lib_AudioOut,
|
||||||
|
"SDL audio queue backed up ({} queued, {} threshold), clearing.", queued,
|
||||||
|
queue_threshold);
|
||||||
|
SDL_ClearAudioStream(stream);
|
||||||
|
// Recalculate the threshold in case this happened because of a device change.
|
||||||
|
queue_threshold = CalculateQueueThreshold();
|
||||||
|
}
|
||||||
if (!SDL_PutAudioStreamData(stream, ptr, static_cast<int>(buffer_size))) {
|
if (!SDL_PutAudioStreamData(stream, ptr, static_cast<int>(buffer_size))) {
|
||||||
LOG_ERROR(Lib_AudioOut, "Failed to output to SDL audio stream: {}", SDL_GetError());
|
LOG_ERROR(Lib_AudioOut, "Failed to output to SDL audio stream: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
@ -70,7 +83,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] u32 CalculateQueueThreshold() const {
|
||||||
|
SDL_AudioSpec discard;
|
||||||
|
int sdl_buffer_frames;
|
||||||
|
if (!SDL_GetAudioDeviceFormat(SDL_GetAudioStreamDevice(stream), &discard,
|
||||||
|
&sdl_buffer_frames)) {
|
||||||
|
LOG_WARNING(Lib_AudioOut, "Failed to get SDL audio stream buffer size: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
sdl_buffer_frames = 0;
|
||||||
|
}
|
||||||
|
return std::max<u32>(buffer_size, sdl_buffer_frames * frame_size) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 frame_size;
|
||||||
u32 buffer_size;
|
u32 buffer_size;
|
||||||
|
u32 queue_threshold;
|
||||||
SDL_AudioStream* stream;
|
SDL_AudioStream* stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user