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
* allocated.
*/
bool SetLengthBytes(uint32_t aLengthBytes) {
bool EnsureLengthBytes(uint32_t aLengthBytes) {
MOZ_ASSERT(aLengthBytes % sizeof(T) == 0,
"Length in bytes is not a whole number of samples");
if (mMemoryBuffer.Length() >= aLengthBytes) {
return true;
}
uint32_t lengthSamples = aLengthBytes / sizeof(T);
uint32_t oldLengthSamples = Capacity();
uint32_t availableRead = AvailableRead();
@ -530,14 +533,17 @@ uint32_t AudioRingBuffer::Clear() {
return mPtr->mFloatRingBuffer->Clear();
}
bool AudioRingBuffer::SetLengthBytes(uint32_t aLengthBytes) {
bool AudioRingBuffer::EnsureLengthBytes(uint32_t aLengthBytes) {
if (mPtr->mFloatRingBuffer) {
return mPtr->mFloatRingBuffer->SetLengthBytes(aLengthBytes);
return mPtr->mFloatRingBuffer->EnsureLengthBytes(aLengthBytes);
}
if (mPtr->mIntRingBuffer) {
return mPtr->mIntRingBuffer->SetLengthBytes(aLengthBytes);
return mPtr->mIntRingBuffer->EnsureLengthBytes(aLengthBytes);
}
if (mPtr->mBackingBuffer) {
if (mPtr->mBackingBuffer->Length() >= aLengthBytes) {
return true;
}
return mPtr->mBackingBuffer->SetLength(aLengthBytes);
}
MOZ_ASSERT_UNREACHABLE("Unexpected");

View File

@ -93,12 +93,12 @@ class AudioRingBuffer final {
uint32_t Clear();
/**
* Set the length of the ring buffer in bytes. Must be divisible by the sample
* size. Will not deallocate memory if the underlying buffer is large enough.
* Returns false if setting the length requires allocating memory and the
* allocation fails.
* Increase the ring buffer size if necessary to at least the specified length
* in bytes. Must be divisible by the sample size.
* Will not deallocate memory if the underlying buffer is large enough.
* 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.

View File

@ -268,11 +268,12 @@ class DynamicResampler final {
}
duration = std::min(cap, duration);
const uint32_t newSizeInFrames =
static_cast<uint32_t>(duration.ToTicksAtRate(mInRate));
bool success = true;
for (auto& b : mInternalInBuffer) {
success = success &&
b.SetLengthBytes(sampleSize * duration.ToTicksAtRate(mInRate));
success = success && b.EnsureLengthBytes(sampleSize * newSizeInFrames);
}
if (success) {
@ -281,16 +282,11 @@ class DynamicResampler final {
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.
NS_WARNING(nsPrintfCString("Failed to allocate a buffer of %u bytes (%u "
"frames). Expect glitches.",
sampleSize * sizeInFrames, sizeInFrames)
sampleSize * newSizeInFrames, newSizeInFrames)
.get());
for (auto& b : mInternalInBuffer) {
MOZ_ALWAYS_TRUE(b.SetLengthBytes(sampleSize * sizeInFrames));
}
return false;
}

View File

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