blob: 5fcaad709c87c33fad04233d3c25a087e4afe51b [file] [log] [blame]
// 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 <algorithm>
#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