Fix looping audio sources not looping seamlessly

This commit is contained in:
2024-05-01 16:34:05 +03:00
parent 2be4d2b717
commit 3237849132
2 changed files with 29 additions and 21 deletions

View File

@@ -428,23 +428,23 @@ void AudioSource::Update()
// Handle streaming buffers queue submit (ensure that clip has loaded the first chunk with audio data) // Handle streaming buffers queue submit (ensure that clip has loaded the first chunk with audio data)
if (_needToUpdateStreamingBuffers && clip->Buffers[_streamingFirstChunk] != AUDIO_BUFFER_ID_INVALID) if (_needToUpdateStreamingBuffers && clip->Buffers[_streamingFirstChunk] != AUDIO_BUFFER_ID_INVALID)
{ {
// Clear flag
_needToUpdateStreamingBuffers = false;
// Get buffers in a queue count // Get buffers in a queue count
int32 numQueuedBuffers; int32 numQueuedBuffers;
AudioBackend::Source::GetQueuedBuffersCount(this, numQueuedBuffers); AudioBackend::Source::GetQueuedBuffersCount(this, numQueuedBuffers);
// Queue missing buffers // Queue missing buffers, make sure there is at least two buffers in queue to avoid gaps in playback
uint32 bufferId; uint32 bufferId;
if (numQueuedBuffers < 1 && (bufferId = clip->Buffers[_streamingFirstChunk]) != AUDIO_BUFFER_ID_INVALID) for (int i = numQueuedBuffers; i < 2; i++)
{ {
AudioBackend::Source::QueueBuffer(this, bufferId); int bufferIndex = (_streamingFirstChunk + i) % clip->Buffers.Count();
if ((bufferId = clip->Buffers[bufferIndex]) != AUDIO_BUFFER_ID_INVALID)
AudioBackend::Source::QueueBuffer(this, bufferId);
else
_needToUpdateStreamingBuffers = true; // The buffer has not been streamed yet, try again later
} }
if (numQueuedBuffers < 2 && _streamingFirstChunk + 1 < clip->Buffers.Count() && (bufferId = clip->Buffers[_streamingFirstChunk + 1]) != AUDIO_BUFFER_ID_INVALID)
{
AudioBackend::Source::QueueBuffer(this, bufferId);
}
// Clear flag
_needToUpdateStreamingBuffers = false;
// Play it if need to // Play it if need to
if (!_isActuallyPlayingSth) if (!_isActuallyPlayingSth)
@@ -469,18 +469,25 @@ void AudioSource::Update()
// Move the chunk pointer (AudioStreamingHandler will request new chunks streaming) // Move the chunk pointer (AudioStreamingHandler will request new chunks streaming)
_streamingFirstChunk += numProcessedBuffers; _streamingFirstChunk += numProcessedBuffers;
if (GetIsLooping())
{
int32 numQueuedBuffers;
AudioBackend::Source::GetQueuedBuffersCount(this, numQueuedBuffers);
if (numQueuedBuffers < 1)
{
// Audio engine unexpectedly stopped playing the clip after queue emptied, restart the clip
_isActuallyPlayingSth = false;
}
}
// Check if reached the end // Check if reached the end
if (_streamingFirstChunk >= clip->Buffers.Count()) if (_streamingFirstChunk >= clip->Buffers.Count())
{ {
// Loop over the clip or end play // Loop over the clip or end play
if (GetIsLooping()) if (GetIsLooping())
{ {
// Move to the begin // Move to the beginning
_streamingFirstChunk = 0; _streamingFirstChunk = 0;
// Stop audio and request buffers re-sync and then play continue
Stop();
Play();
} }
else else
{ {

View File

@@ -195,14 +195,15 @@ int32 AudioStreamingHandler::CalculateResidency(StreamableResource* resource, fl
if (src->Clip == clip && src->GetState() != AudioSource::States::Stopped) if (src->Clip == clip && src->GetState() != AudioSource::States::Stopped)
{ {
// Stream the current and the next chunk if could be used in a while // Stream the current and the next chunk if could be used in a while
const int32 chunk = src->_streamingFirstChunk;
ASSERT(Math::IsInRange(chunk, 0, chunksCount));
chunksMask[chunk] = true;
const float StreamingDstSec = 2.0f; // TODO: make it configurable via StreamingSettings const float StreamingDstSec = 2.0f; // TODO: make it configurable via StreamingSettings
if (chunk + 1 < chunksCount && src->GetTime() + StreamingDstSec >= clip->GetBufferStartTime(src->_streamingFirstChunk)) const int32 firstChunk = src->_streamingFirstChunk;
const int32 nextChunk = (firstChunk + 1) % chunksCount;
ASSERT(Math::IsInRange(firstChunk, 0, chunksCount));
chunksMask[firstChunk] = true;
if (firstChunk != nextChunk && src->GetTime() + StreamingDstSec >= clip->GetBufferStartTime(firstChunk))
{ {
chunksMask[chunk + 1] = true; chunksMask[nextChunk] = true;
} }
} }
} }