mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-20 00:20:37 +00:00
Bug 1844181 - Implement AudioRingBuffer::PrependSilence. r=padenot
This can be handy when AudioDriftCorrection resamples the first time. In order to calculate how many frames to prepend in order to get the buffer to contain exactly the number of desired pre-buffer frames *after* resampling, so the DriftController starts out with an error = 0. Differential Revision: https://phabricator.services.mozilla.com/D188182
This commit is contained in:
parent
e5450c80ab
commit
9035b6a0a3
@ -32,6 +32,14 @@ class RingBuffer final {
|
||||
MOZ_ASSERT(!mStorage.IsEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `aSamples` number of zeros in the buffer, before any existing data.
|
||||
*/
|
||||
uint32_t PrependSilence(uint32_t aSamples) {
|
||||
MOZ_ASSERT(aSamples);
|
||||
return Prepend(Span<T>(), aSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `aSamples` number of zeros in the buffer.
|
||||
*/
|
||||
@ -49,6 +57,42 @@ class RingBuffer final {
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Copy `aSamples` number of elements from `aBuffer` to the beginning of the
|
||||
* RingBuffer. If `aBuffer` is empty prepend `aSamples` of zeros.
|
||||
*/
|
||||
uint32_t Prepend(const Span<const T>& aBuffer, uint32_t aSamples) {
|
||||
MOZ_ASSERT(aSamples > 0);
|
||||
MOZ_ASSERT(aBuffer.IsEmpty() || aBuffer.Length() == aSamples);
|
||||
|
||||
if (IsFull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t toWrite = std::min(AvailableWrite(), aSamples);
|
||||
uint32_t part2 = std::min(mReadIndex, toWrite);
|
||||
uint32_t part1 = toWrite - part2;
|
||||
|
||||
Span<T> part2Buffer = mStorage.Subspan(mReadIndex - part2, part2);
|
||||
Span<T> part1Buffer = mStorage.Subspan(Capacity() - part1, part1);
|
||||
|
||||
if (!aBuffer.IsEmpty()) {
|
||||
Span<const T> fromPart1 = aBuffer.To(part1);
|
||||
Span<const T> fromPart2 = aBuffer.Subspan(part1, part2);
|
||||
|
||||
CopySpan(part1Buffer, fromPart1);
|
||||
CopySpan(part2Buffer, fromPart2);
|
||||
} else {
|
||||
// aBuffer is empty, prepend zeros.
|
||||
PodZero(part1Buffer.Elements(), part1Buffer.Length());
|
||||
PodZero(part2Buffer.Elements(), part2Buffer.Length());
|
||||
}
|
||||
|
||||
mReadIndex = NextIndex(mReadIndex, Capacity() - toWrite);
|
||||
|
||||
return toWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy `aSamples` number of elements from `aBuffer` to the RingBuffer. If
|
||||
* `aBuffer` is empty append `aSamples` of zeros.
|
||||
@ -352,6 +396,18 @@ uint32_t AudioRingBuffer::Write(const AudioRingBuffer& aBuffer,
|
||||
aSamples);
|
||||
}
|
||||
|
||||
uint32_t AudioRingBuffer::PrependSilence(uint32_t aSamples) {
|
||||
MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
|
||||
mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
|
||||
MOZ_ASSERT(!mPtr->mBackingBuffer);
|
||||
if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
|
||||
MOZ_ASSERT(!mPtr->mFloatRingBuffer);
|
||||
return mPtr->mIntRingBuffer->PrependSilence(aSamples);
|
||||
}
|
||||
MOZ_ASSERT(!mPtr->mIntRingBuffer);
|
||||
return mPtr->mFloatRingBuffer->PrependSilence(aSamples);
|
||||
}
|
||||
|
||||
uint32_t AudioRingBuffer::WriteSilence(uint32_t aSamples) {
|
||||
MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
|
||||
mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
|
||||
|
@ -47,6 +47,11 @@ class AudioRingBuffer final {
|
||||
*/
|
||||
uint32_t Write(const AudioRingBuffer& aBuffer, uint32_t aSamples);
|
||||
|
||||
/**
|
||||
* Write `aSamples` number of zeros before the beginning of the existing data.
|
||||
*/
|
||||
uint32_t PrependSilence(uint32_t aSamples);
|
||||
|
||||
/**
|
||||
* Write `aSamples` number of zeros.
|
||||
*/
|
||||
|
@ -5,10 +5,12 @@
|
||||
|
||||
#include "AudioRingBuffer.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using testing::ElementsAre;
|
||||
|
||||
TEST(TestAudioRingBuffer, BasicFloat)
|
||||
{
|
||||
@ -991,3 +993,103 @@ TEST(TestAudioRingBuffer, WriteFromRingFloat)
|
||||
EXPECT_FLOAT_EQ(out2[i], in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestAudioRingBuffer, PrependSilenceWrapsFloat)
|
||||
{
|
||||
AudioRingBuffer rb(9 * sizeof(float));
|
||||
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
|
||||
|
||||
float in[6] = {.2, .3, .4, .5, .6, .7};
|
||||
uint32_t rv = rb.Write(Span(in, 6));
|
||||
EXPECT_EQ(rv, 6u);
|
||||
|
||||
float out[8] = {};
|
||||
auto outSpan = Span(out, 8);
|
||||
rv = rb.Read(outSpan.Subspan(0, 1));
|
||||
EXPECT_EQ(rv, 1u);
|
||||
|
||||
// PrependSilence will have to wrap around the start and put the silent
|
||||
// samples at indices 0 and 8 of the ring buffer.
|
||||
rv = rb.PrependSilence(2);
|
||||
EXPECT_EQ(rv, 2u);
|
||||
|
||||
rv = rb.Read(outSpan.Subspan(1, 7));
|
||||
EXPECT_EQ(rv, 7u);
|
||||
|
||||
EXPECT_THAT(out, ElementsAre(.2, 0, 0, .3, .4, .5, .6, .7));
|
||||
}
|
||||
|
||||
TEST(TestAudioRingBuffer, PrependSilenceWrapsShort)
|
||||
{
|
||||
AudioRingBuffer rb(9 * sizeof(short));
|
||||
rb.SetSampleFormat(AUDIO_FORMAT_S16);
|
||||
|
||||
short in[6] = {2, 3, 4, 5, 6, 7};
|
||||
uint32_t rv = rb.Write(Span(in, 6));
|
||||
EXPECT_EQ(rv, 6u);
|
||||
|
||||
short out[8] = {};
|
||||
auto outSpan = Span(out, 8);
|
||||
rv = rb.Read(outSpan.Subspan(0, 1));
|
||||
EXPECT_EQ(rv, 1u);
|
||||
|
||||
// PrependSilence will have to wrap around the start and put the silent
|
||||
// samples at indices 0 and 8 of the ring buffer.
|
||||
rv = rb.PrependSilence(2);
|
||||
EXPECT_EQ(rv, 2u);
|
||||
|
||||
rv = rb.Read(outSpan.Subspan(1, 7));
|
||||
EXPECT_EQ(rv, 7u);
|
||||
|
||||
EXPECT_THAT(out, ElementsAre(2, 0, 0, 3, 4, 5, 6, 7));
|
||||
}
|
||||
|
||||
TEST(TestAudioRingBuffer, PrependSilenceNoWrapFloat)
|
||||
{
|
||||
AudioRingBuffer rb(9 * sizeof(float));
|
||||
rb.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
|
||||
|
||||
float in[6] = {.2, .3, .4, .5, .6, .7};
|
||||
uint32_t rv = rb.Write(Span(in, 6));
|
||||
EXPECT_EQ(rv, 6u);
|
||||
|
||||
float out[8] = {};
|
||||
auto outSpan = Span(out, 8);
|
||||
rv = rb.Read(outSpan.To(4));
|
||||
EXPECT_EQ(rv, 4u);
|
||||
|
||||
// PrependSilence will put the silent samples at indices 2 and 3 of the ring
|
||||
// buffer.
|
||||
rv = rb.PrependSilence(2);
|
||||
EXPECT_EQ(rv, 2u);
|
||||
|
||||
rv = rb.Read(outSpan.Subspan(4, 4));
|
||||
EXPECT_EQ(rv, 4u);
|
||||
|
||||
EXPECT_THAT(out, ElementsAre(.2, .3, .4, .5, 0, 0, .6, .7));
|
||||
}
|
||||
|
||||
TEST(TestAudioRingBuffer, PrependSilenceNoWrapShort)
|
||||
{
|
||||
AudioRingBuffer rb(9 * sizeof(short));
|
||||
rb.SetSampleFormat(AUDIO_FORMAT_S16);
|
||||
|
||||
short in[6] = {2, 3, 4, 5, 6, 7};
|
||||
uint32_t rv = rb.Write(Span(in, 6));
|
||||
EXPECT_EQ(rv, 6u);
|
||||
|
||||
short out[8] = {};
|
||||
auto outSpan = Span(out, 8);
|
||||
rv = rb.Read(outSpan.To(4));
|
||||
EXPECT_EQ(rv, 4u);
|
||||
|
||||
// PrependSilence will put the silent samples at indices 2 and 3 of the ring
|
||||
// buffer.
|
||||
rv = rb.PrependSilence(2);
|
||||
EXPECT_EQ(rv, 2u);
|
||||
|
||||
rv = rb.Read(outSpan.Subspan(4, 4));
|
||||
EXPECT_EQ(rv, 4u);
|
||||
|
||||
EXPECT_THAT(out, ElementsAre(2, 3, 4, 5, 0, 0, 6, 7));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user