diff options
Diffstat (limited to 'dom/media/gtest/TestAudioRingBuffer.cpp')
-rw-r--r-- | dom/media/gtest/TestAudioRingBuffer.cpp | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/dom/media/gtest/TestAudioRingBuffer.cpp b/dom/media/gtest/TestAudioRingBuffer.cpp new file mode 100644 index 0000000000..1eb33df384 --- /dev/null +++ b/dom/media/gtest/TestAudioRingBuffer.cpp @@ -0,0 +1,993 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AudioRingBuffer.h" + +#include "gtest/gtest.h" +#include "mozilla/PodOperations.h" + +using namespace mozilla; + +TEST(TestAudioRingBuffer, BasicFloat) +{ + AudioRingBuffer ringBuffer(11 * sizeof(float)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + uint32_t rv = ringBuffer.WriteSilence(4); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + float in[4] = {.1, .2, .3, .4}; + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.WriteSilence(4); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + float out[4] = {}; + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 4u); + EXPECT_EQ(ringBuffer.AvailableRead(), 6u); + for (float f : out) { + EXPECT_FLOAT_EQ(f, 0.0); + } + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 2; ++i) { + EXPECT_FLOAT_EQ(out[i], 0.0); + } + + rv = ringBuffer.Clear(); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); +} + +TEST(TestAudioRingBuffer, BasicShort) +{ + AudioRingBuffer ringBuffer(11 * sizeof(short)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16); + + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + uint32_t rv = ringBuffer.WriteSilence(4); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + short in[4] = {1, 2, 3, 4}; + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.WriteSilence(4); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + short out[4] = {}; + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 4u); + EXPECT_EQ(ringBuffer.AvailableRead(), 6u); + for (float f : out) { + EXPECT_EQ(f, 0); + } + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 2; ++i) { + EXPECT_EQ(out[i], 0); + } + + rv = ringBuffer.Clear(); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); +} + +TEST(TestAudioRingBuffer, BasicFloat2) +{ + AudioRingBuffer ringBuffer(11 * sizeof(float)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + float in[4] = {.1, .2, .3, .4}; + uint32_t rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + float out[4] = {}; + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } + + // WriteIndex = 12 + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 8)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 8)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } + + // WriteIndex = 16 + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); +} + +TEST(TestAudioRingBuffer, BasicShort2) +{ + AudioRingBuffer ringBuffer(11 * sizeof(int16_t)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16); + + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + int16_t in[4] = {1, 2, 3, 4}; + uint32_t rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + int16_t out[4] = {}; + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_EQ(in[i], out[i]); + } + + // WriteIndex = 12 + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.Read(Span(out, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 8)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_EQ(in[i], out[i]); + } + + rv = ringBuffer.Read(Span(out, 8)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_EQ(in[i], out[i]); + } + + // WriteIndex = 16 + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 6u); + EXPECT_EQ(ringBuffer.AvailableRead(), 4u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 2u); + EXPECT_EQ(ringBuffer.AvailableRead(), 8u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); + + rv = ringBuffer.Write(Span(in, 4)); + EXPECT_EQ(rv, 0u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 0u); + EXPECT_EQ(ringBuffer.AvailableRead(), 10u); +} + +TEST(TestAudioRingBuffer, NoCopyFloat) +{ + AudioRingBuffer ringBuffer(11 * sizeof(float)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7}; + ringBuffer.Write(Span(in, 6)); + // v ReadIndex + // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0] + + float out[10] = {}; + float* out_ptr = out; + + uint32_t rv = + ringBuffer.ReadNoCopy([&out_ptr](const Span<const float> aInBuffer) { + PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length()); + out_ptr += aInBuffer.Length(); + return aInBuffer.Length(); + }); + EXPECT_EQ(rv, 6u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i]); + } + + ringBuffer.Write(Span(in, 8)); + // Now the buffer contains: + // [x0: .5, x1: .6, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4 + // ^ ReadIndex + out_ptr = out; // reset the pointer before lambdas reuse + rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const float> aInBuffer) { + PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length()); + out_ptr += aInBuffer.Length(); + return aInBuffer.Length(); + }); + EXPECT_EQ(rv, 8u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i]); + } +} + +TEST(TestAudioRingBuffer, NoCopyShort) +{ + AudioRingBuffer ringBuffer(11 * sizeof(short)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16); + + short in[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + ringBuffer.Write(Span(in, 6)); + // v ReadIndex + // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0] + + short out[10] = {}; + short* out_ptr = out; + + uint32_t rv = + ringBuffer.ReadNoCopy([&out_ptr](const Span<const short> aInBuffer) { + PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length()); + out_ptr += aInBuffer.Length(); + return aInBuffer.Length(); + }); + EXPECT_EQ(rv, 6u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i]); + } + + ringBuffer.Write(Span(in, 8)); + // Now the buffer contains: + // [x0: 5, x1: 6, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4 + // ^ ReadIndex + out_ptr = out; // reset the pointer before lambdas reuse + rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const short> aInBuffer) { + PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length()); + out_ptr += aInBuffer.Length(); + return aInBuffer.Length(); + }); + EXPECT_EQ(rv, 8u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i]); + } +} + +TEST(TestAudioRingBuffer, NoCopyFloat2) +{ + AudioRingBuffer ringBuffer(11 * sizeof(float)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7}; + ringBuffer.Write(Span(in, 6)); + // v ReadIndex + // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0] + + float out[10] = {}; + float* out_ptr = out; + uint32_t total_frames = 3; + + uint32_t rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const float>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // v ReadIndex + // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0] + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 7u); + EXPECT_EQ(ringBuffer.AvailableRead(), 3u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const float>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0] + // ^ ReadIndex + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i + 3], in[i + 3]); + } + + ringBuffer.Write(Span(in, 8)); + // Now the buffer contains: + // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4 + // ^ ReadIndex + + // reset the pointer before lambdas reuse + out_ptr = out; + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const float>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // [x0: .5, x1: .6, x2: .2, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4 + // ^ ReadIndex + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 5u); + EXPECT_EQ(ringBuffer.AvailableRead(), 5u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const float>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // v ReadIndex + // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4 + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i + 3], in[i + 3]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const float>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // v ReadIndex + // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4, + // x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4 + EXPECT_EQ(rv, 2u); + EXPECT_EQ(total_frames, 1u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i + 6], in[i + 6]); + } +} + +TEST(TestAudioRingBuffer, NoCopyShort2) +{ + AudioRingBuffer ringBuffer(11 * sizeof(short)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16); + + short in[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + ringBuffer.Write(Span(in, 6)); + // v ReadIndex + // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0] + + short out[10] = {}; + short* out_ptr = out; + uint32_t total_frames = 3; + + uint32_t rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const short>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // v ReadIndex + // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0] + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 7u); + EXPECT_EQ(ringBuffer.AvailableRead(), 3u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const short>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: .0] + // ^ ReadIndex + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i + 3], in[i + 3]); + } + + ringBuffer.Write(Span(in, 8)); + // Now the buffer contains: + // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4 + // ^ ReadIndex + + // reset the pointer before lambdas reuse + out_ptr = out; + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const short>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // [x0: 5, x1: 6, x2: 2, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4 + // ^ ReadIndex + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 5u); + EXPECT_EQ(ringBuffer.AvailableRead(), 5u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const short>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // v ReadIndex + // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4 + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i + 3], in[i + 3]); + } + + total_frames = 3; + rv = ringBuffer.ReadNoCopy( + [&out_ptr, &total_frames](const Span<const short>& aInBuffer) { + uint32_t inFramesUsed = + std::min<uint32_t>(total_frames, aInBuffer.Length()); + PodMove(out_ptr, aInBuffer.data(), inFramesUsed); + out_ptr += inFramesUsed; + total_frames -= inFramesUsed; + return inFramesUsed; + }); + // Now the buffer contains: + // v ReadIndex + // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4, + // x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4 + EXPECT_EQ(rv, 2u); + EXPECT_EQ(total_frames, 1u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i + 6], in[i + 6]); + } +} + +TEST(TestAudioRingBuffer, DiscardFloat) +{ + AudioRingBuffer ringBuffer(11 * sizeof(float)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7}; + ringBuffer.Write(Span(in, 8)); + + uint32_t rv = ringBuffer.Discard(3); + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 5u); + EXPECT_EQ(ringBuffer.AvailableRead(), 5u); + + float out[8] = {}; + rv = ringBuffer.Read(Span(out, 3)); + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i + 3]); + } + + rv = ringBuffer.Discard(3); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + ringBuffer.WriteSilence(4); + rv = ringBuffer.Discard(6); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); +} + +TEST(TestAudioRingBuffer, DiscardShort) +{ + AudioRingBuffer ringBuffer(11 * sizeof(short)); + ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16); + + short in[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + ringBuffer.Write(Span(in, 8)); + + uint32_t rv = ringBuffer.Discard(3); + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 5u); + EXPECT_EQ(ringBuffer.AvailableRead(), 5u); + + short out[8] = {}; + rv = ringBuffer.Read(Span(out, 3)); + EXPECT_EQ(rv, 3u); + EXPECT_TRUE(!ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 8u); + EXPECT_EQ(ringBuffer.AvailableRead(), 2u); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i + 3]); + } + + rv = ringBuffer.Discard(3); + EXPECT_EQ(rv, 2u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); + + ringBuffer.WriteSilence(4); + rv = ringBuffer.Discard(6); + EXPECT_EQ(rv, 4u); + EXPECT_TRUE(ringBuffer.IsEmpty()); + EXPECT_TRUE(!ringBuffer.IsFull()); + EXPECT_EQ(ringBuffer.AvailableWrite(), 10u); + EXPECT_EQ(ringBuffer.AvailableRead(), 0u); +} + +TEST(TestRingBuffer, WriteFromRing1) +{ + AudioRingBuffer ringBuffer1(11 * sizeof(float)); + ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + AudioRingBuffer ringBuffer2(11 * sizeof(float)); + ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + float in[4] = {.1, .2, .3, .4}; + uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4)); + EXPECT_EQ(rv, 4u); + + EXPECT_EQ(ringBuffer2.AvailableRead(), 0u); + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + + float out[4] = {}; + rv = ringBuffer2.Read(Span<float>(out, 4)); + EXPECT_EQ(rv, 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } +} + +TEST(TestRingBuffer, WriteFromRing2) +{ + AudioRingBuffer ringBuffer1(11 * sizeof(float)); + ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + AudioRingBuffer ringBuffer2(11 * sizeof(float)); + ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + // Advance the index + ringBuffer2.WriteSilence(8); + ringBuffer2.Clear(); + + float in[4] = {.1, .2, .3, .4}; + uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4)); + EXPECT_EQ(rv, 4u); + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + + float out[4] = {}; + rv = ringBuffer2.Read(Span<float>(out, 4)); + EXPECT_EQ(rv, 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } +} + +TEST(TestRingBuffer, WriteFromRing3) +{ + AudioRingBuffer ringBuffer1(11 * sizeof(float)); + ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + AudioRingBuffer ringBuffer2(11 * sizeof(float)); + ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + // Advance the index + ringBuffer2.WriteSilence(8); + ringBuffer2.Clear(); + ringBuffer2.WriteSilence(4); + ringBuffer2.Clear(); + + float in[4] = {.1, .2, .3, .4}; + uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4)); + EXPECT_EQ(rv, 4u); + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + + float out[4] = {}; + rv = ringBuffer2.Read(Span<float>(out, 4)); + EXPECT_EQ(rv, 4u); + for (uint32_t i = 0; i < 4; ++i) { + EXPECT_FLOAT_EQ(in[i], out[i]); + } +} + +TEST(TestAudioRingBuffer, WriteFromRingShort) +{ + AudioRingBuffer ringBuffer1(11 * sizeof(short)); + ringBuffer1.SetSampleFormat(AUDIO_FORMAT_S16); + + short in[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + uint32_t rv = ringBuffer1.Write(Span(in, 8)); + EXPECT_EQ(rv, 8u); + + AudioRingBuffer ringBuffer2(11 * sizeof(short)); + ringBuffer2.SetSampleFormat(AUDIO_FORMAT_S16); + + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 8u); + + short out[4] = {}; + rv = ringBuffer2.Read(Span(out, 4)); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out[i], in[i]); + } + + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 8u); + + ringBuffer1.Discard(4); + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 8u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 4u); + + short out2[8] = {}; + rv = ringBuffer2.Read(Span(out2, 8)); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_EQ(out2[i], in[i]); + } +} + +TEST(TestAudioRingBuffer, WriteFromRingFloat) +{ + AudioRingBuffer ringBuffer1(11 * sizeof(float)); + ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7}; + uint32_t rv = ringBuffer1.Write(Span(in, 8)); + EXPECT_EQ(rv, 8u); + + AudioRingBuffer ringBuffer2(11 * sizeof(float)); + ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32); + + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 8u); + + float out[4] = {}; + rv = ringBuffer2.Read(Span(out, 4)); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out[i], in[i]); + } + + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 4u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 8u); + + ringBuffer1.Discard(4); + rv = ringBuffer2.Write(ringBuffer1, 4); + EXPECT_EQ(rv, 4u); + EXPECT_EQ(ringBuffer2.AvailableRead(), 8u); + EXPECT_EQ(ringBuffer1.AvailableRead(), 4u); + + float out2[8] = {}; + rv = ringBuffer2.Read(Span(out2, 8)); + for (uint32_t i = 0; i < rv; ++i) { + EXPECT_FLOAT_EQ(out2[i], in[i]); + } +} |