Fixed a heisenbug in AudioManager that was actually caused by a bug in SDL_AudioStreamAvailable().

This commit is contained in:
Leon Styhre 2021-07-15 18:07:01 +02:00
parent 5c0cf89ac1
commit b4d85c5b34

View file

@ -306,16 +306,37 @@ void AudioManager::clearStream()
// to empty the stream. // to empty the stream.
// SDL_AudioStreamClear(sConversionStream); // SDL_AudioStreamClear(sConversionStream);
mIsClearingStream = true; // If sSoundVector is empty it means we are shutting down. In this case don't attempt
int length = sAudioFormat.samples * 4; // to clear the stream as this could lead to a crash.
if (sSoundVector.empty())
return;
while (SDL_AudioStreamAvailable(sConversionStream) > 0) { mIsClearingStream = true;
std::vector<Uint8> readBuffer(length);
int processedLength = // This code is required as there's seemingly a bug in SDL_AudioStreamAvailable().
SDL_AudioStreamGet(sConversionStream, static_cast<void*>(&readBuffer.at(0)), length); // The function sometimes returns 0 even if there is data left in the buffer, possibly
if (processedLength <= 0) // because the remaining data is less than the configured sample size. It happens almost
break; // permanently on NetBSD but also on at least Linux from time to time. Adding some data
// to the stream buffer to get above this threshold before calling the function will
// return the proper number. So adding 10000 as we do here would give a return value of
// for instance 10880 instead of 0, assuming there were 880 bytes of data left in the buffer.
// Fortunately the SDL_AudioStreamGet() function acts correctly on any arbitrary sample size
// so we can actually clear the entire buffer. If this workaround was not implemented, there
// would be a sound glitch when some samples from the previous video would play any time a
// new video was started (assuming the issue was triggered be some remaining buffer data).
std::vector<Uint8> writeBuffer(10000);
if (SDL_AudioStreamPut(sConversionStream, reinterpret_cast<const void*>(&writeBuffer.at(0)),
10000) == -1) {
LOG(LogError) << "Failed to put samples in the conversion stream:";
LOG(LogError) << SDL_GetError();
mIsClearingStream = false;
return;
} }
int length = SDL_AudioStreamAvailable(sConversionStream);
std::vector<Uint8> readBuffer(length);
SDL_AudioStreamGet(sConversionStream, static_cast<void*>(&readBuffer.at(0)), length);
mIsClearingStream = false; mIsClearingStream = false;
} }