// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "services/audio/delay_buffer.h" #include #include "media/base/audio_bus.h" #include "testing/gtest/include/gtest/gtest.h" namespace audio { namespace { constexpr int kChannels = 1; constexpr int kMaxFrames = 32; #define EXPECT_BUS_VALUES_EQ(bus, begin, end, value) \ { \ const auto IsValue = [](float x) { return x == (value); }; \ EXPECT_TRUE(std::all_of((bus)->channel(0) + (begin), \ (bus)->channel(0) + (end) - (begin), IsValue)); \ } TEST(DelayBufferTest, RecordsAMaximumNumberOfFrames) { DelayBuffer buffer(kMaxFrames); ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition()); constexpr int frames_per_bus = kMaxFrames / 4; const auto bus = media::AudioBus::Create(kChannels, frames_per_bus); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0); // Fill the buffer. DelayBuffer::FrameTicks position = 0; for (int i = 0; i < 4; ++i) { buffer.Write(position, *bus, 1.0); position += frames_per_bus; EXPECT_EQ(0, buffer.GetBeginPosition()); EXPECT_EQ(position, buffer.GetEndPosition()); } // Writing just one more bus should cause the leading frames to be dropped. buffer.Write(position, *bus, 1.0); position += frames_per_bus; EXPECT_EQ(position - kMaxFrames, buffer.GetBeginPosition()); EXPECT_EQ(position, buffer.GetEndPosition()); // Now, simulate a gap in the recording by recording the next bus late. position += frames_per_bus * 2; buffer.Write(position, *bus, 1.0); position += frames_per_bus; EXPECT_EQ(position - kMaxFrames, buffer.GetBeginPosition()); EXPECT_EQ(position, buffer.GetEndPosition()); } TEST(DelayBufferTest, ReadsSilenceIfNothingWasRecorded) { DelayBuffer buffer(kMaxFrames); ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition()); DelayBuffer::FrameTicks position = 0; constexpr int frames_per_bus = kMaxFrames / 4; const auto bus = media::AudioBus::Create(kChannels, frames_per_bus); for (int i = 0; i < 10; ++i) { // Set data in the bus to confirm it is all going to be overwritten. std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0); buffer.Read(position, frames_per_bus, bus.get()); EXPECT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition()); EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0); position += frames_per_bus; } } TEST(DelayBufferTest, ReadsSilenceIfOutsideRecordedRange) { DelayBuffer buffer(kMaxFrames); ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition()); constexpr int frames_per_bus = kMaxFrames / 4; const auto bus = media::AudioBus::Create(kChannels, frames_per_bus); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0); // Fill the buffer. DelayBuffer::FrameTicks position = 0; for (int i = 0; i < 4; ++i) { buffer.Write(position, *bus, 1.0); position += frames_per_bus; } EXPECT_EQ(0, buffer.GetBeginPosition()); EXPECT_EQ(position, buffer.GetEndPosition()); // Read before the begin position and expect to get silence. std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(-kMaxFrames, frames_per_bus, bus.get()); EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0); // Read at a position one before the begin position. Expect the first sample // to be 0.0, and the rest 1.0. std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(buffer.GetBeginPosition() - 1, frames_per_bus, bus.get()); EXPECT_EQ(0.0, bus->channel(0)[0]); EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0); // Read at a position where the last sample should be 0.0 and the rest 1.0. std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(buffer.GetEndPosition() - frames_per_bus + 1, frames_per_bus, bus.get()); EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus - 1, 1.0); EXPECT_EQ(0.0, bus->channel(0)[frames_per_bus - 1]); // Read after the end position and expect to get silence. std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(kMaxFrames, frames_per_bus, bus.get()); EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0); } TEST(DelayBufferTest, ReadsGapsInRecording) { DelayBuffer buffer(kMaxFrames); ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition()); constexpr int frames_per_bus = kMaxFrames / 4; const auto bus = media::AudioBus::Create(kChannels, frames_per_bus); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0); // Fill the buffer, but with a gap in the third quarter of it. DelayBuffer::FrameTicks record_position = 0; for (int i = 0; i < 4; ++i) { if (i != 2) { buffer.Write(record_position, *bus, 1.0); } record_position += frames_per_bus; } EXPECT_EQ(0, buffer.GetBeginPosition()); EXPECT_EQ(record_position, buffer.GetEndPosition()); // Read through the whole range, but offset by one frame early. Confirm the // silence gap appears in the right place. DelayBuffer::FrameTicks read_position = -1; std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(read_position, frames_per_bus, bus.get()); read_position += frames_per_bus; EXPECT_EQ(0.0, bus->channel(0)[0]); EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(read_position, frames_per_bus, bus.get()); read_position += frames_per_bus; EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 1.0); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(read_position, frames_per_bus, bus.get()); read_position += frames_per_bus; EXPECT_EQ(1.0, bus->channel(0)[0]); // The gap begins. EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 0.0); std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5); buffer.Read(read_position, frames_per_bus, bus.get()); read_position += frames_per_bus; EXPECT_EQ(0.0, bus->channel(0)[0]); // The gap ends. EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0); } } // namespace } // namespace audio