diff --git a/engine/core/src/streaming.c b/engine/core/src/streaming.c index 1fb4a5881..58744a526 100644 --- a/engine/core/src/streaming.c +++ b/engine/core/src/streaming.c @@ -116,7 +116,7 @@ uint32_t Streaming_GetSample(streaming_channel_t *stream, void *data, uint32_t s } else { - data = memcpy(data, stream->sample_ptr, (size * stream->data_size)); + memcpy(data, stream->sample_ptr, (size * stream->data_size)); // Set the new sample pointer stream->sample_ptr = stream->sample_ptr + (size * stream->data_size); } @@ -157,7 +157,10 @@ uint32_t Streaming_GetAvailableSampleNB(streaming_channel_t *stream) uint32_t Streaming_GetAvailableSampleNBUntilEndBuffer(streaming_channel_t *stream) { LUOS_ASSERT(stream != NULL); - int32_t nb_available_sample = ((uintptr_t)stream->data_ptr - (uintptr_t)stream->sample_ptr) / stream->data_size; + // Narrow the pointer difference to a signed value before dividing, the same + // way Streaming_GetAvailableSampleNB does. Dividing the unsigned difference + // first loses the sign, and the loop below is never taken. + int32_t nb_available_sample = ((int32_t)((uintptr_t)stream->data_ptr - (uintptr_t)stream->sample_ptr)) / stream->data_size; if (nb_available_sample < 0) { // The buffer have looped @@ -210,12 +213,9 @@ uint32_t Streaming_RmvAvailableSampleNB(streaming_channel_t *stream, uint32_t si } else { + // Landing exactly on the end of the ring buffer is handled by the branch + // above, which takes over as soon as the new pointer reaches it. stream->sample_ptr = (void *)((uintptr_t)stream->sample_ptr + (size * stream->data_size)); - if (stream->sample_ptr == stream->end_ring_buffer) - { - // If we are exactly at the end of the ring buffer, we need to loop - stream->sample_ptr = stream->ring_buffer; - } } return Streaming_GetAvailableSampleNB(stream); } diff --git a/test/tests_core/test_streaming/main.c b/test/tests_core/test_streaming/main.c index 229bc19e3..0fd9efdd3 100644 --- a/test/tests_core/test_streaming/main.c +++ b/test/tests_core/test_streaming/main.c @@ -526,6 +526,28 @@ void unittest_Streaming_GetAvailableSampleNBUntilEndBuffer(void) TEST_ASSERT_TRUE(false); } } + NEW_TEST_CASE("Test Streaming_GetAvailableSampleNBUntilEndBuffer buffer loop case on a 3 byte data size"); + { + // 10 samples of 3 bytes. A data size that is not a power of two makes the + // sign of the pointer difference matter: dividing it before narrowing it + // to int32_t turns the negative difference into a large positive number, + // so the loop branch below is never taken. + uint8_t buffer3[30]; + streaming_channel_t channel3 = {0}; + TRY + { + channel3 = Streaming_CreateChannel(buffer3, 10, 3); + // data_ptr one sample behind sample_ptr, so the buffer has looped + channel3.sample_ptr = (void *)((uintptr_t)channel3.ring_buffer + 27); + channel3.data_ptr = (void *)((uintptr_t)channel3.ring_buffer + 24); + TEST_ASSERT_EQUAL(9, Streaming_GetAvailableSampleNB(&channel3)); + TEST_ASSERT_EQUAL(1, Streaming_GetAvailableSampleNBUntilEndBuffer(&channel3)); + } + CATCH + { + TEST_ASSERT_TRUE(false); + } + } } void unittest_Streaming_AddAvailableSampleNB(void)