Bug 1890689 Change AudioRingBuffer::SetLengthBytes() to EnsureLengthBytes() r=pehrsons

This now provides reasonable behavior if shorter lengths should be passed.
SetLengthBytes() did not move buffered data to within a shorter new length and
would not update mWriteIndexhandle.  TestAudioRingBuffer.EnsureLengthShorter
would crash with

Assertion failure:
aStart <= len && (aLength == dynamic_extent || (aStart + aLength <= len)),
at obj/dist/include/mozilla/Span.h:660

SetLengthBytes() was called with shorter lengths only on memory allocation
failure.  This was not necessary.

The warning is adjusted to indicate the size of the allocation attempted.

Depends on D207659

Differential Revision: https://phabricator.services.mozilla.com/D207660
This commit is contained in:
Karl Tomlinson 2024-04-18 02:24:04 +00:00
parent 9a1ff71623
commit 6f843408fd
4 changed files with 57 additions and 29 deletions

View File

@ -270,10 +270,13 @@ class RingBuffer final {
* Re-allocates memory if a larger buffer is requested than what is already * Re-allocates memory if a larger buffer is requested than what is already
* allocated. * allocated.
*/ */
bool SetLengthBytes(uint32_t aLengthBytes) { bool EnsureLengthBytes(uint32_t aLengthBytes) {
MOZ_ASSERT(aLengthBytes % sizeof(T) == 0, MOZ_ASSERT(aLengthBytes % sizeof(T) == 0,
"Length in bytes is not a whole number of samples"); "Length in bytes is not a whole number of samples");
if (mMemoryBuffer.Length() >= aLengthBytes) {
return true;
}
uint32_t lengthSamples = aLengthBytes / sizeof(T); uint32_t lengthSamples = aLengthBytes / sizeof(T);
uint32_t oldLengthSamples = Capacity(); uint32_t oldLengthSamples = Capacity();
uint32_t availableRead = AvailableRead(); uint32_t availableRead = AvailableRead();
@ -530,14 +533,17 @@ uint32_t AudioRingBuffer::Clear() {
return mPtr->mFloatRingBuffer->Clear(); return mPtr->mFloatRingBuffer->Clear();
} }
bool AudioRingBuffer::SetLengthBytes(uint32_t aLengthBytes) { bool AudioRingBuffer::EnsureLengthBytes(uint32_t aLengthBytes) {
if (mPtr->mFloatRingBuffer) { if (mPtr->mFloatRingBuffer) {
return mPtr->mFloatRingBuffer->SetLengthBytes(aLengthBytes); return mPtr->mFloatRingBuffer->EnsureLengthBytes(aLengthBytes);
} }
if (mPtr->mIntRingBuffer) { if (mPtr->mIntRingBuffer) {
return mPtr->mIntRingBuffer->SetLengthBytes(aLengthBytes); return mPtr->mIntRingBuffer->EnsureLengthBytes(aLengthBytes);
} }
if (mPtr->mBackingBuffer) { if (mPtr->mBackingBuffer) {
if (mPtr->mBackingBuffer->Length() >= aLengthBytes) {
return true;
}
return mPtr->mBackingBuffer->SetLength(aLengthBytes); return mPtr->mBackingBuffer->SetLength(aLengthBytes);
} }
MOZ_ASSERT_UNREACHABLE("Unexpected"); MOZ_ASSERT_UNREACHABLE("Unexpected");

View File

@ -93,12 +93,12 @@ class AudioRingBuffer final {
uint32_t Clear(); uint32_t Clear();
/** /**
* Set the length of the ring buffer in bytes. Must be divisible by the sample * Increase the ring buffer size if necessary to at least the specified length
* size. Will not deallocate memory if the underlying buffer is large enough. * in bytes. Must be divisible by the sample size.
* Returns false if setting the length requires allocating memory and the * Will not deallocate memory if the underlying buffer is large enough.
* allocation fails. * Returns false if memory allocation is required and fails.
*/ */
bool SetLengthBytes(uint32_t aLengthBytes); bool EnsureLengthBytes(uint32_t aLengthBytes);
/** /**
* Return the number of samples this buffer can hold. * Return the number of samples this buffer can hold.

View File

@ -268,11 +268,12 @@ class DynamicResampler final {
} }
duration = std::min(cap, duration); duration = std::min(cap, duration);
const uint32_t newSizeInFrames =
static_cast<uint32_t>(duration.ToTicksAtRate(mInRate));
bool success = true; bool success = true;
for (auto& b : mInternalInBuffer) { for (auto& b : mInternalInBuffer) {
success = success && success = success && b.EnsureLengthBytes(sampleSize * newSizeInFrames);
b.SetLengthBytes(sampleSize * duration.ToTicksAtRate(mInRate));
} }
if (success) { if (success) {
@ -281,16 +282,11 @@ class DynamicResampler final {
return true; return true;
} }
const uint32_t sizeInFrames =
static_cast<uint32_t>(mSetBufferDuration.ToTicksAtRate(mInRate));
// Allocating an input buffer failed. We stick with the old buffer size. // Allocating an input buffer failed. We stick with the old buffer size.
NS_WARNING(nsPrintfCString("Failed to allocate a buffer of %u bytes (%u " NS_WARNING(nsPrintfCString("Failed to allocate a buffer of %u bytes (%u "
"frames). Expect glitches.", "frames). Expect glitches.",
sampleSize * sizeInFrames, sizeInFrames) sampleSize * newSizeInFrames, newSizeInFrames)
.get()); .get());
for (auto& b : mInternalInBuffer) {
MOZ_ALWAYS_TRUE(b.SetLengthBytes(sampleSize * sizeInFrames));
}
return false; return false;
} }

View File

@ -1094,7 +1094,7 @@ TEST(TestAudioRingBuffer, PrependSilenceNoWrapShort)
EXPECT_THAT(out, ElementsAre(2, 3, 4, 5, 0, 0, 6, 7)); EXPECT_THAT(out, ElementsAre(2, 3, 4, 5, 0, 0, 6, 7));
} }
TEST(TestAudioRingBuffer, SetLengthBytesNoWrapFloat) TEST(TestAudioRingBuffer, EnsureLengthBytesNoWrapFloat)
{ {
AudioRingBuffer rb(6 * sizeof(float)); AudioRingBuffer rb(6 * sizeof(float));
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32); rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
@ -1106,7 +1106,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesNoWrapFloat)
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_EQ(rb.Capacity(), 6u); EXPECT_EQ(rb.Capacity(), 6u);
EXPECT_TRUE(rb.SetLengthBytes(11 * sizeof(float))); EXPECT_TRUE(rb.EnsureLengthBytes(11 * sizeof(float)));
float out[10] = {}; float out[10] = {};
rv = rb.Read(Span(out, 10)); rv = rb.Read(Span(out, 10));
EXPECT_EQ(rv, 5u); EXPECT_EQ(rv, 5u);
@ -1116,7 +1116,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesNoWrapFloat)
EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, 0, 0, 0, 0, 0)); EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, 0, 0, 0, 0, 0));
} }
TEST(TestAudioRingBuffer, SetLengthBytesNoWrapShort) TEST(TestAudioRingBuffer, EnsureLengthBytesNoWrapShort)
{ {
AudioRingBuffer rb(6 * sizeof(short)); AudioRingBuffer rb(6 * sizeof(short));
rb.SetSampleFormat(AUDIO_FORMAT_S16); rb.SetSampleFormat(AUDIO_FORMAT_S16);
@ -1128,7 +1128,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesNoWrapShort)
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_EQ(rb.Capacity(), 6u); EXPECT_EQ(rb.Capacity(), 6u);
EXPECT_TRUE(rb.SetLengthBytes(11 * sizeof(short))); EXPECT_TRUE(rb.EnsureLengthBytes(11 * sizeof(short)));
short out[10] = {}; short out[10] = {};
rv = rb.Read(Span(out, 10)); rv = rb.Read(Span(out, 10));
EXPECT_EQ(rv, 5u); EXPECT_EQ(rv, 5u);
@ -1138,7 +1138,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesNoWrapShort)
EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 0, 0, 0, 0, 0)); EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 0, 0, 0, 0, 0));
} }
TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartFloat) TEST(TestAudioRingBuffer, EnsureLengthBytesWrap1PartFloat)
{ {
AudioRingBuffer rb(6 * sizeof(float)); AudioRingBuffer rb(6 * sizeof(float));
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32); rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
@ -1158,7 +1158,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartFloat)
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_TRUE(rb.SetLengthBytes(11 * sizeof(float))); EXPECT_TRUE(rb.EnsureLengthBytes(11 * sizeof(float)));
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 5u); EXPECT_EQ(rb.AvailableWrite(), 5u);
@ -1175,7 +1175,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartFloat)
EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, .6, .7, 0, 0, 0)); EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, .6, .7, 0, 0, 0));
} }
TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartShort) TEST(TestAudioRingBuffer, EnsureLengthBytesWrap1PartShort)
{ {
AudioRingBuffer rb(6 * sizeof(short)); AudioRingBuffer rb(6 * sizeof(short));
rb.SetSampleFormat(AUDIO_FORMAT_S16); rb.SetSampleFormat(AUDIO_FORMAT_S16);
@ -1195,7 +1195,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartShort)
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_TRUE(rb.SetLengthBytes(11 * sizeof(short))); EXPECT_TRUE(rb.EnsureLengthBytes(11 * sizeof(short)));
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 5u); EXPECT_EQ(rb.AvailableWrite(), 5u);
@ -1212,7 +1212,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap1PartShort)
EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 6, 7, 0, 0, 0)); EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 6, 7, 0, 0, 0));
} }
TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsFloat) TEST(TestAudioRingBuffer, EnsureLengthBytesWrap2PartsFloat)
{ {
AudioRingBuffer rb(6 * sizeof(float)); AudioRingBuffer rb(6 * sizeof(float));
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32); rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
@ -1232,7 +1232,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsFloat)
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_TRUE(rb.SetLengthBytes(8 * sizeof(float))); EXPECT_TRUE(rb.EnsureLengthBytes(8 * sizeof(float)));
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 2u); EXPECT_EQ(rb.AvailableWrite(), 2u);
@ -1249,7 +1249,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsFloat)
EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, .6, .7, 0)); EXPECT_THAT(out, ElementsAre(.1, .2, .3, .4, .5, .6, .7, 0));
} }
TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsShort) TEST(TestAudioRingBuffer, EnsureLengthBytesWrap2PartsShort)
{ {
AudioRingBuffer rb(6 * sizeof(short)); AudioRingBuffer rb(6 * sizeof(short));
rb.SetSampleFormat(AUDIO_FORMAT_S16); rb.SetSampleFormat(AUDIO_FORMAT_S16);
@ -1269,7 +1269,7 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsShort)
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 0u); EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_TRUE(rb.SetLengthBytes(8 * sizeof(short))); EXPECT_TRUE(rb.EnsureLengthBytes(8 * sizeof(short)));
EXPECT_EQ(rb.AvailableRead(), 5u); EXPECT_EQ(rb.AvailableRead(), 5u);
EXPECT_EQ(rb.AvailableWrite(), 2u); EXPECT_EQ(rb.AvailableWrite(), 2u);
@ -1285,3 +1285,29 @@ TEST(TestAudioRingBuffer, SetLengthBytesWrap2PartsShort)
EXPECT_EQ(rb.Capacity(), 8u); EXPECT_EQ(rb.Capacity(), 8u);
EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 6, 7, 0)); EXPECT_THAT(out, ElementsAre(1, 2, 3, 4, 5, 6, 7, 0));
} }
TEST(TestAudioRingBuffer, EnsureLengthShorter)
{
AudioRingBuffer rb(5 * sizeof(float));
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
float in[5] = {.1, .2, .3, .4, .5};
EXPECT_EQ(rb.Write(Span(in, 5)), 4u);
EXPECT_EQ(rb.AvailableRead(), 4u);
EXPECT_EQ(rb.AvailableWrite(), 0u);
EXPECT_EQ(rb.Capacity(), 5u);
float out[5] = {};
EXPECT_EQ(rb.Read(Span(out, 3)), 3u);
EXPECT_THAT(out, ElementsAre(.1, .2, .3, 0, 0));
EXPECT_EQ(rb.AvailableRead(), 1u);
EXPECT_EQ(rb.AvailableWrite(), 3u);
EXPECT_TRUE(rb.EnsureLengthBytes(3 * sizeof(float)));
EXPECT_EQ(rb.AvailableRead(), 1u);
EXPECT_EQ(rb.AvailableWrite(), 3u);
EXPECT_EQ(rb.Capacity(), 5u);
EXPECT_EQ(rb.Write(Span(in, 5)), 3u);
EXPECT_EQ(rb.Read(Span(out, 5)), 4u);
EXPECT_THAT(out, ElementsAre(.4, .1, .2, .3, 0));
}