// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/audio/playback_rate_shifter.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromecast {
namespace media {
namespace {
constexpr int kSampleRate = 48000;
constexpr int64_t kMaxTimestampError = 50;
constexpr int kReadSize = 512;
} // namespace
class PlaybackRateShifterTest : public testing::Test, public AudioProvider {
public:
PlaybackRateShifterTest()
: rate_shifter_(this,
::media::CHANNEL_LAYOUT_MONO,
1,
kSampleRate,
kReadSize) {
srand(12345);
}
~PlaybackRateShifterTest() override = default;
int FillFrames(int num_frames,
int64_t playout_timestamp,
float* const* channel_data) override {
if (expected_playout_timestamp_ != INT64_MIN) {
int64_t error = playout_timestamp - expected_playout_timestamp_;
EXPECT_LT(std::abs(error), kMaxTimestampError)
<< "Playout timestamp error from BufferedFrames() is " << error;
expected_playout_timestamp_ = INT64_MIN;
}
if (next_playout_timestamp_ != INT64_MIN) {
int64_t error = playout_timestamp - next_playout_timestamp_;
EXPECT_LT(std::abs(error), kMaxTimestampError)
<< "Playout timestamp error from FillFrames() is " << error;
}
next_playout_timestamp_ =
playout_timestamp +
FramesToTime(num_frames) / rate_shifter_.playback_rate();
float* channel = channel_data[0];
for (int i = 0; i < num_frames; ++i) {
channel[i] = base::RandDouble();
}
filled_ += num_frames;
return num_frames;
}
size_t num_channels() const override { return 1; }
int sample_rate() const override { return kSampleRate; }
void Read(int num_frames) {
int64_t request_timestamp = FramesToTime(num_read_);
double buffered = rate_shifter_.BufferedFrames();
int64_t filled_before = filled_;
// No more than 50ms of buffer (plus 1 read).
EXPECT_LT(buffered,
(kSampleRate / 20 + kReadSize) / rate_shifter_.playback_rate());
expected_playout_timestamp_ = request_timestamp + FramesToTime(buffered);
float buffer[num_frames];
float* data[1] = {buffer};
int read = rate_shifter_.FillFrames(num_frames, request_timestamp, data);
EXPECT_EQ(read, num_frames);
num_read_ += read;
int64_t filled_during_read = filled_ - filled_before;
int64_t expected_next_playout_timestamp =
request_timestamp +
FramesToTime(buffered +
filled_during_read / rate_shifter_.playback_rate());
int64_t next_playout_timestamp =
FramesToTime(num_read_ + rate_shifter_.BufferedFrames());
int64_t error = expected_next_playout_timestamp - next_playout_timestamp;
EXPECT_LT(std::abs(error), kMaxTimestampError)
<< "Playout timestamp error before/after read is " << error;
}
void ReadAll(int total_frames) {
int read = 0;
while (read < total_frames) {
int frames = (rand() % 32 + 8) * 16;
Read(frames);
read += frames;
}
}
int64_t FramesToTime(int64_t frames) {
return frames * 1000000 / kSampleRate;
}
void SetPlaybackRate(double rate) {
LOG(INFO) << "Set rate to " << rate;
rate_shifter_.SetPlaybackRate(rate);
next_playout_timestamp_ = INT64_MIN;
}
protected:
PlaybackRateShifter rate_shifter_;
int64_t next_playout_timestamp_ = INT64_MIN;
int64_t num_read_ = 0;
int64_t filled_ = 0;
int64_t expected_playout_timestamp_ = INT64_MIN;
int64_t next_expected_playout_timestamp_ = INT64_MIN;
};
TEST_F(PlaybackRateShifterTest, Normal) {
SetPlaybackRate(1.0);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, Slower) {
SetPlaybackRate(0.7);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, Slower2) {
SetPlaybackRate(0.5);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, Faster) {
SetPlaybackRate(1.5);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, Faster2) {
SetPlaybackRate(2.0);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, IncreaseTo1) {
SetPlaybackRate(0.7);
ReadAll(kSampleRate);
SetPlaybackRate(1.0);
ReadAll(kSampleRate / 2);
}
TEST_F(PlaybackRateShifterTest, IncreaseFrom1) {
SetPlaybackRate(1.0);
ReadAll(kSampleRate);
SetPlaybackRate(1.5);
ReadAll(kSampleRate / 2);
}
TEST_F(PlaybackRateShifterTest, DecreaseTo1) {
SetPlaybackRate(1.3);
ReadAll(kSampleRate);
SetPlaybackRate(1.0);
ReadAll(kSampleRate / 2);
}
TEST_F(PlaybackRateShifterTest, DecreaseFrom1) {
SetPlaybackRate(1.0);
ReadAll(kSampleRate);
SetPlaybackRate(0.6);
ReadAll(kSampleRate / 2);
}
TEST_F(PlaybackRateShifterTest, Increasing) {
SetPlaybackRate(0.5);
ReadAll(kSampleRate);
SetPlaybackRate(0.7);
ReadAll(kSampleRate);
SetPlaybackRate(0.99);
ReadAll(kSampleRate);
SetPlaybackRate(1.0);
ReadAll(kSampleRate);
SetPlaybackRate(1.01);
ReadAll(kSampleRate);
SetPlaybackRate(1.4);
ReadAll(kSampleRate);
SetPlaybackRate(2.0);
ReadAll(kSampleRate);
}
TEST_F(PlaybackRateShifterTest, Decreasing) {
SetPlaybackRate(2.0);
ReadAll(kSampleRate);
SetPlaybackRate(1.6);
ReadAll(kSampleRate);
SetPlaybackRate(1.01);
ReadAll(kSampleRate);
SetPlaybackRate(1.0);
ReadAll(kSampleRate);
SetPlaybackRate(0.99);
ReadAll(kSampleRate);
SetPlaybackRate(0.64);
ReadAll(kSampleRate);
SetPlaybackRate(0.5);
ReadAll(kSampleRate);
}
} // namespace media
} // namespace chromecast