blob: da7b186e1c71f98be3ca9f7014245347aaed59bf [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "src/media/audio/audio_core/ring_buffer.h"
#include <lib/zx/clock.h>
#include <gtest/gtest.h>
#include "src/media/audio/lib/clock/clone_mono.h"
#include "src/media/audio/lib/clock/testing/clock_test.h"
namespace media::audio {
namespace {
const Format kDefaultFormat =
Format::Create(fuchsia::media::AudioStreamType{
.sample_format = fuchsia::media::AudioSampleFormat::FLOAT,
.channels = 2,
.frames_per_second = 48000,
})
.take_value();
// 10ms @ 48khz
const uint32_t kRingBufferFrameCount = 480;
class InputRingBufferTest : public ::testing::Test {
protected:
void SetUp() override {
const auto& format = kDefaultFormat;
auto timeline_function = fbl::MakeRefCounted<VersionedTimelineFunction>(
TimelineFunction(0, zx::time(0).get(), Fixed(format.frames_per_second()).raw_value(),
zx::sec(1).to_nsecs()));
auto endpoints = BaseRingBuffer::AllocateSoftwareBuffer(
format, std::move(timeline_function), reference_clock(), kRingBufferFrameCount,
[this]() { return safe_read_frame_; });
ring_buffer_ = endpoints.reader;
ASSERT_TRUE(ring_buffer());
}
ReadableRingBuffer* ring_buffer() const { return ring_buffer_.get(); }
AudioClock& reference_clock() { return audio_clock_; }
// Advance to the given time.
void Advance(zx::time ref_time) {
auto pts_to_frac_frame = ring_buffer_->ref_time_to_frac_presentation_frame().timeline_function;
safe_read_frame_ = Fixed::FromRaw(pts_to_frac_frame.Apply(ref_time.get())).Floor();
}
private:
std::shared_ptr<ReadableRingBuffer> ring_buffer_;
AudioClock audio_clock_ =
AudioClock::DeviceFixed(clock::CloneOfMonotonic(), AudioClock::kMonotonicDomain);
int64_t safe_read_frame_ = -1;
};
class OutputRingBufferTest : public ::testing::Test {
protected:
void SetUp() override {
const auto& format = kDefaultFormat;
auto timeline_function = fbl::MakeRefCounted<VersionedTimelineFunction>(
TimelineFunction(0, zx::time(0).get(), Fixed(format.frames_per_second()).raw_value(),
zx::sec(1).to_nsecs()));
auto endpoints = BaseRingBuffer::AllocateSoftwareBuffer(
format, std::move(timeline_function), reference_clock(), kRingBufferFrameCount,
[this]() { return safe_write_frame_; });
ring_buffer_ = endpoints.writer;
ASSERT_TRUE(ring_buffer());
}
WritableRingBuffer* ring_buffer() const { return ring_buffer_.get(); }
AudioClock& reference_clock() { return audio_clock_; }
// Advance to the given time.
void Advance(zx::time ref_time) {
auto pts_to_frac_frame = ring_buffer_->ref_time_to_frac_presentation_frame().timeline_function;
safe_write_frame_ = Fixed::FromRaw(pts_to_frac_frame.Apply(ref_time.get())).Floor();
}
private:
std::shared_ptr<WritableRingBuffer> ring_buffer_;
AudioClock audio_clock_ =
AudioClock::DeviceFixed(clock::CloneOfMonotonic(), AudioClock::kMonotonicDomain);
int64_t safe_write_frame_ = 0;
};
TEST_F(InputRingBufferTest, ReadEmptyRing) {
Advance(zx::time(0));
auto buffer = ring_buffer()->ReadLock(Fixed(0), 1);
ASSERT_FALSE(buffer);
}
TEST_F(InputRingBufferTest, ReadFullyExpiredBuffer) {
// After 20ms, the ring will have been filled twice. If we request the first 480 frames then we
// should get no buffer returned since all those frames are now unavailable.
Advance(zx::time(0) + zx::msec(20));
auto buffer = ring_buffer()->ReadLock(Fixed(0), kRingBufferFrameCount);
ASSERT_FALSE(buffer);
}
TEST_F(InputRingBufferTest, ReadNotYetAvailableBuffer) {
// After 10ms, 480 frames will have been produced (0-479). The 480th frame is not yet available
// so we should get no buffer.
Advance(zx::time(0) + zx::msec(10));
auto buffer = ring_buffer()->ReadLock(Fixed(480), 1);
ASSERT_FALSE(buffer);
}
TEST_F(InputRingBufferTest, ReadFullyAvailableRegion) {
// After 1ms we expect 48 frames to be available to read at the start of the buffer.
Advance(zx::time(0) + zx::msec(1));
auto buffer = ring_buffer()->ReadLock(Fixed(0), 48);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 0u);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
TEST_F(InputRingBufferTest, ReadPartialRegion) {
// After 1ms we expect 48 frames to be available to read at the start of the buffer. If we ask for
// 96 we should get a buffer that contains only the 48 available frames.
Advance(zx::time(0) + zx::msec(1));
auto buffer = ring_buffer()->ReadLock(Fixed(0), 96);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 0u);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
TEST_F(InputRingBufferTest, SkipExpiredFrames) {
// At 11ms we'll have written the entire ring + 48 more samples, so the first 48 frames are lost.
// Test that the returned buffer correctly skips those 48 frames.
Advance(zx::time(0) + zx::msec(11));
auto buffer = ring_buffer()->ReadLock(Fixed(0), 96);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 48u);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
TEST_F(InputRingBufferTest, ReadAfterTruncateBufferAtEndOfTheRing) {
// After 11ms 528 frames will have been put into the ring. We try to read the last 96 frames,
// which spans the last 48 frames in the ring and then the first 48 frames at the start of the
// ring again. Test our buffer is truncated for the first 48 frames requested at the end of the
// ring.
Advance(zx::time(0) + zx::msec(11));
auto buffer = ring_buffer()->ReadLock(Fixed(432), 96);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 432u);
EXPECT_EQ(buffer->length().Floor(), 48u);
// Now read that last 48 frames at the start of the ring again.
buffer = ring_buffer()->ReadLock(Fixed(480), 48);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 480u);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
TEST_F(InputRingBufferTest, ReadNegativeFrame) {
Advance(zx::time(0));
auto buffer = ring_buffer()->ReadLock(Fixed(-10), 10);
ASSERT_TRUE(buffer);
auto rb_start_address = reinterpret_cast<uintptr_t>(ring_buffer()->virt());
auto buffer_address = reinterpret_cast<uintptr_t>(buffer->payload());
EXPECT_EQ(buffer_address,
rb_start_address + ((ring_buffer()->frames() - 10) * kDefaultFormat.bytes_per_frame()));
EXPECT_EQ(buffer->start().Floor(), -10);
EXPECT_EQ(buffer->length().Floor(), 10u);
}
TEST_F(OutputRingBufferTest, WriteEmptyRing) {
Advance(zx::time(0));
auto buffer = ring_buffer()->WriteLock(0, 1);
ASSERT_TRUE(buffer);
ASSERT_EQ(0u, buffer->start().Floor());
ASSERT_EQ(1u, buffer->length().Floor());
}
TEST_F(OutputRingBufferTest, WriteFullyExpiredBuffer) {
// After 10ms the hardware will have already consumed the first kRingBufferFrameCount frames.
// Attempting to get a buffer into that region should not be successful.
Advance(zx::time(0) + zx::msec(10));
auto buffer = ring_buffer()->WriteLock(0, kRingBufferFrameCount);
ASSERT_FALSE(buffer);
}
TEST_F(OutputRingBufferTest, WriteNotYetAvailableBuffer) {
// Trying to get a buffer more than |kRingBufferFrameCount| frames into the future will fail as it
// would cause use to clobber frames not yet consumed by the hardware.
Advance(zx::time(0));
auto buffer = ring_buffer()->WriteLock(kRingBufferFrameCount, 1);
ASSERT_FALSE(buffer);
}
TEST_F(OutputRingBufferTest, WriteFullyAvailableRegion) {
// At time 0, we should be able to get a full buffer into the ring.
Advance(zx::time(0));
auto buffer = ring_buffer()->WriteLock(0, kRingBufferFrameCount);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 0u);
EXPECT_EQ(buffer->length().Floor(), kRingBufferFrameCount);
}
TEST_F(OutputRingBufferTest, WritePartialRegion) {
// After 1ms we expect 48 frames to have been consumed, so we can only get a buffer into the final
// 48 requested frames.
Advance(zx::time(0) + zx::msec(1));
auto buffer = ring_buffer()->WriteLock(0, 96);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 48u);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
TEST_F(OutputRingBufferTest, WriteAfterTruncateBufferAtEndOfTheRing) {
// After 9ms, the first 432 frames will have been consumed by hardware. Attempting to read the
// next 96 frames will wrap around the ring, so we should only get the first 48 returned.
Advance(zx::time(0) + zx::msec(9));
auto buffer = ring_buffer()->WriteLock(432, 96);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), 432u);
EXPECT_EQ(buffer->length().Floor(), 48u);
// Now read that last 48 frames at the start of the ring again.
buffer = ring_buffer()->WriteLock(kRingBufferFrameCount, 48);
ASSERT_TRUE(buffer);
EXPECT_EQ(buffer->start().Floor(), kRingBufferFrameCount);
EXPECT_EQ(buffer->length().Floor(), 48u);
}
} // namespace
} // namespace media::audio