Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Unified Diff: chromecast/media/cma/backend/multizone_backend_unittest.cc

Issue 2908893002: [Chromecast] Make MultizoneBackendTest work on AMP devices. (Closed)
Patch Set: Change number of seconds back to int. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chromecast/media/cma/backend/multizone_backend_unittest.cc
diff --git a/chromecast/media/cma/backend/multizone_backend_unittest.cc b/chromecast/media/cma/backend/multizone_backend_unittest.cc
index b471fa693d8dc9ef77568dd6299bbf7497f956e2..f3cfb91285f16efca8d9d41dbc8240a693a58897 100644
--- a/chromecast/media/cma/backend/multizone_backend_unittest.cc
+++ b/chromecast/media/cma/backend/multizone_backend_unittest.cc
@@ -11,8 +11,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -40,9 +42,8 @@ class MultizoneBackendTest;
namespace {
-const int64_t kMicrosecondsPerSecond = 1000 * 1000;
// Total length of test, in microseconds.
-const int64_t kPushTimeUs = 2 * kMicrosecondsPerSecond;
+const int64_t kPushTimeUs = 2 * base::Time::kMicrosecondsPerSecond;
const int64_t kStartPts = 0;
const int64_t kMaxRenderingDelayErrorUs = 200;
const int kNumEffectsStreams = 1;
@@ -54,27 +55,23 @@ class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
public:
BufferFeeder(const AudioConfig& config,
bool effects_only,
- const base::Closure& eos_cb);
+ base::OnceClosure eos_cb,
+ int playback_rate_change_count);
~BufferFeeder() override {}
- void Initialize(float playback_rate);
- void Start();
+ void Initialize();
+ void Start(float playback_rate);
void Stop();
- int64_t max_rendering_delay_error_us() {
- return max_rendering_delay_error_us_;
- }
-
- int64_t max_positive_rendering_delay_error_us() {
- return max_positive_rendering_delay_error_us_;
- }
-
- int64_t max_negative_rendering_delay_error_us() {
- return max_negative_rendering_delay_error_us_;
- }
-
- int64_t average_rendering_delay_error_us() {
- return total_rendering_delay_error_us_ / sample_count_;
+ int64_t GetMaxRenderingDelayErrorUs() {
+ int64_t max = 0;
+ for (int64_t error : errors_) {
+ if (error == kNoTimestamp) {
+ continue;
+ }
+ max = std::max(max, std::abs(error));
+ }
+ return max;
}
private:
@@ -103,21 +100,19 @@ class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
const AudioConfig config_;
const bool effects_only_;
- const base::Closure eos_cb_;
- double original_playback_rate_;
- double playback_rate_;
- int64_t max_rendering_delay_error_us_;
- int64_t max_positive_rendering_delay_error_us_;
- int64_t max_negative_rendering_delay_error_us_;
- int64_t total_rendering_delay_error_us_;
- size_t sample_count_;
+ base::OnceClosure eos_cb_;
+ const int64_t push_limit_us_;
+ const int64_t playback_rate_change_interval_us_;
+ float original_playback_rate_;
+ float playback_rate_;
+ std::vector<int64_t> errors_;
bool feeding_completed_;
- std::unique_ptr<TaskRunnerImpl> task_runner_;
+ TaskRunnerImpl task_runner_;
std::unique_ptr<MediaPipelineBackend> backend_;
MediaPipelineBackend::AudioDecoder* decoder_;
- int64_t push_limit_us_;
int64_t last_push_length_us_;
int64_t pushed_us_;
+ int64_t pushed_us_when_rate_changed_;
int64_t next_push_playback_timestamp_;
scoped_refptr<DecoderBufferBase> pending_buffer_;
base::ThreadChecker thread_checker_;
@@ -127,8 +122,8 @@ class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
} // namespace
-using TestParams = std::tr1::tuple<int, // sample rate
- float>; // playback rate
+using TestParams =
+ std::tr1::tuple<int /* sample rate */, float /* playback rate */>;
class MultizoneBackendTest : public testing::TestWithParam<TestParams> {
public:
@@ -155,11 +150,12 @@ class MultizoneBackendTest : public testing::TestWithParam<TestParams> {
void AddEffectsStreams();
- void Initialize(int sample_rate, float playback_rate);
- void Start();
+ void Initialize(int sample_rate, int playback_rate_change_count);
+ void Start(float playback_rate);
void OnEndOfStream();
private:
+ base::MessageLoop message_loop_;
std::vector<std::unique_ptr<BufferFeeder>> effects_feeders_;
std::unique_ptr<BufferFeeder> audio_feeder_;
@@ -170,34 +166,31 @@ namespace {
BufferFeeder::BufferFeeder(const AudioConfig& config,
bool effects_only,
- const base::Closure& eos_cb)
+ base::OnceClosure eos_cb,
+ int playback_rate_change_count)
: config_(config),
effects_only_(effects_only),
- eos_cb_(eos_cb),
- original_playback_rate_(1.0),
- playback_rate_(1.0),
- max_rendering_delay_error_us_(0),
- max_positive_rendering_delay_error_us_(0),
- max_negative_rendering_delay_error_us_(0),
- total_rendering_delay_error_us_(0),
- sample_count_(0),
+ eos_cb_(std::move(eos_cb)),
+ push_limit_us_(effects_only_ ? 0 : kPushTimeUs),
+ playback_rate_change_interval_us_(push_limit_us_ /
+ (playback_rate_change_count + 1)),
+ original_playback_rate_(1.0f),
+ playback_rate_(1.0f),
feeding_completed_(false),
- task_runner_(new TaskRunnerImpl()),
decoder_(nullptr),
- push_limit_us_(effects_only_ ? 0 : kPushTimeUs),
last_push_length_us_(0),
pushed_us_(0),
+ pushed_us_when_rate_changed_(0),
next_push_playback_timestamp_(kNoTimestamp) {
- CHECK(!eos_cb_.is_null());
+ CHECK(eos_cb_);
}
-void BufferFeeder::Initialize(float playback_rate) {
- original_playback_rate_ = playback_rate_ = playback_rate;
+void BufferFeeder::Initialize() {
MediaPipelineDeviceParams params(
MediaPipelineDeviceParams::kModeIgnorePts,
effects_only_ ? MediaPipelineDeviceParams::kAudioStreamSoundEffects
: MediaPipelineDeviceParams::kAudioStreamNormal,
- task_runner_.get(), AudioContentType::kMedia,
+ &task_runner_, AudioContentType::kMedia,
::media::AudioDeviceDescription::kDefaultDeviceId);
backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params));
CHECK(backend_);
@@ -208,13 +201,18 @@ void BufferFeeder::Initialize(float playback_rate) {
decoder_->SetDelegate(this);
ASSERT_TRUE(backend_->Initialize());
- ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate));
}
-void BufferFeeder::Start() {
+void BufferFeeder::Start(float playback_rate) {
+ // AMP devices only support playback rates between 0.5 and 2.0.
+ ASSERT_GE(playback_rate, 0.5f);
+ ASSERT_LE(playback_rate, 2.0f);
+ original_playback_rate_ = playback_rate_ = playback_rate;
ASSERT_TRUE(backend_->Start(kStartPts));
+ ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&BufferFeeder::FeedBuffer, base::Unretained(this)));
}
void BufferFeeder::Stop() {
@@ -227,15 +225,21 @@ void BufferFeeder::FeedBuffer() {
if (feeding_completed_)
return;
- if (!effects_only_ && pushed_us_ >= push_limit_us_ / 2 &&
- playback_rate_ == original_playback_rate_) {
- if (original_playback_rate_ < 1.0) {
+ if (!effects_only_ && pushed_us_ > pushed_us_when_rate_changed_ +
+ playback_rate_change_interval_us_) {
+ pushed_us_when_rate_changed_ = pushed_us_;
+ if (playback_rate_ != original_playback_rate_) {
+ playback_rate_ = original_playback_rate_;
+ } else if (original_playback_rate_ < 1.0) {
playback_rate_ = original_playback_rate_ * 2;
- ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_));
} else {
playback_rate_ = original_playback_rate_ / 2;
- ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_));
}
+ ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_));
+ // Changing the playback rate will change the rendering delay on devices
+ // where playback rate changes apply to audio that has already been pushed.
+ // Ignore the next rendering delay.
+ next_push_playback_timestamp_ = kNoTimestamp;
}
if (!effects_only_ && pushed_us_ >= push_limit_us_) {
@@ -247,7 +251,7 @@ void BufferFeeder::FeedBuffer() {
int size_bytes = (rand() % 96 + 32) * 16;
int num_samples =
size_bytes / (config_.bytes_per_channel * config_.channel_number);
- last_push_length_us_ = num_samples * kMicrosecondsPerSecond /
+ last_push_length_us_ = num_samples * base::Time::kMicrosecondsPerSecond /
(config_.samples_per_second * playback_rate_);
scoped_refptr<::media::DecoderBuffer> silence_buffer(
new ::media::DecoderBuffer(size_bytes));
@@ -265,7 +269,7 @@ void BufferFeeder::FeedBuffer() {
void BufferFeeder::OnEndOfStream() {
DCHECK(thread_checker_.CalledOnValidThread());
- eos_cb_.Run();
+ std::move(eos_cb_).Run();
}
void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
@@ -277,6 +281,7 @@ void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
MediaPipelineBackend::AudioDecoder::RenderingDelay delay =
decoder_->GetRenderingDelay();
+ int64_t error = kNoTimestamp;
if (delay.timestamp_microseconds == kNoTimestamp) {
next_push_playback_timestamp_ = kNoTimestamp;
} else {
@@ -288,22 +293,11 @@ void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
next_push_playback_timestamp_ + last_push_length_us_;
next_push_playback_timestamp_ =
delay.timestamp_microseconds + delay.delay_microseconds;
- int64_t error = next_push_playback_timestamp_ -
- expected_next_push_playback_timestamp;
-
- max_rendering_delay_error_us_ =
- std::max(max_rendering_delay_error_us_, std::abs(error));
- total_rendering_delay_error_us_ += std::abs(error);
- if (error >= 0) {
- max_positive_rendering_delay_error_us_ =
- std::max(max_positive_rendering_delay_error_us_, error);
- } else {
- max_negative_rendering_delay_error_us_ =
- std::min(max_negative_rendering_delay_error_us_, error);
- }
- sample_count_++;
+ error = next_push_playback_timestamp_ -
+ expected_next_push_playback_timestamp;
}
}
+ errors_.push_back(error);
}
pushed_us_ += last_push_length_us_;
@@ -311,7 +305,8 @@ void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
return;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&BufferFeeder::FeedBuffer, base::Unretained(this)));
}
} // namespace
@@ -320,19 +315,21 @@ MultizoneBackendTest::MultizoneBackendTest() {}
MultizoneBackendTest::~MultizoneBackendTest() {}
-void MultizoneBackendTest::Initialize(int sample_rate, float playback_rate) {
+void MultizoneBackendTest::Initialize(int sample_rate,
+ int playback_rate_change_count) {
AudioConfig config;
config.codec = kCodecPCM;
- config.sample_format = kSampleFormatS32;
+ config.sample_format = kSampleFormatPlanarF32;
config.channel_number = 2;
config.bytes_per_channel = 4;
config.samples_per_second = sample_rate;
- audio_feeder_.reset(
- new BufferFeeder(config, false /* effects_only */,
- base::Bind(&MultizoneBackendTest::OnEndOfStream,
- base::Unretained(this))));
- audio_feeder_->Initialize(playback_rate);
+ audio_feeder_ = base::MakeUnique<BufferFeeder>(
+ config, false /* effects_only */,
+ base::BindOnce(&MultizoneBackendTest::OnEndOfStream,
+ base::Unretained(this)),
+ playback_rate_change_count);
+ audio_feeder_->Initialize();
}
void MultizoneBackendTest::AddEffectsStreams() {
@@ -344,18 +341,19 @@ void MultizoneBackendTest::AddEffectsStreams() {
effects_config.samples_per_second = 48000;
for (int i = 0; i < kNumEffectsStreams; ++i) {
- std::unique_ptr<BufferFeeder> feeder(new BufferFeeder(
- effects_config, true /* effects_only */, base::Bind(&IgnoreEos)));
- feeder->Initialize(1.0f);
+ auto feeder = base::MakeUnique<BufferFeeder>(
+ effects_config, true /* effects_only */, base::BindOnce(&IgnoreEos), 0);
+ feeder->Initialize();
effects_feeders_.push_back(std::move(feeder));
}
}
-void MultizoneBackendTest::Start() {
+void MultizoneBackendTest::Start(float playback_rate) {
for (auto& feeder : effects_feeders_)
- feeder->Start();
+ feeder->Start(1.0f);
CHECK(audio_feeder_);
- audio_feeder_->Start();
+ audio_feeder_->Start(playback_rate);
+ base::RunLoop().Run();
}
void MultizoneBackendTest::OnEndOfStream() {
@@ -365,26 +363,24 @@ void MultizoneBackendTest::OnEndOfStream() {
base::MessageLoop::current()->QuitWhenIdle();
- EXPECT_LT(audio_feeder_->max_rendering_delay_error_us(),
- kMaxRenderingDelayErrorUs)
- << "Max positive rendering delay error: "
- << audio_feeder_->max_positive_rendering_delay_error_us()
- << "\nMax negative rendering delay error: "
- << audio_feeder_->max_negative_rendering_delay_error_us()
- << "\nAverage rendering delay error: "
- << audio_feeder_->average_rendering_delay_error_us();
+ EXPECT_LT(audio_feeder_->GetMaxRenderingDelayErrorUs(),
+ kMaxRenderingDelayErrorUs);
}
TEST_P(MultizoneBackendTest, RenderingDelay) {
- std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
const TestParams& params = GetParam();
int sample_rate = testing::get<0>(params);
float playback_rate = testing::get<1>(params);
- Initialize(sample_rate, playback_rate);
+ Initialize(sample_rate, 1 /* playback_rate_change_count */);
AddEffectsStreams();
- Start();
- base::RunLoop().Run();
+ Start(playback_rate);
+}
+
+TEST_F(MultizoneBackendTest, RenderingDelayWithMultipleRateChanges) {
+ Initialize(48000 /* sample_rate */, 10 /* playback_rate_change_count */);
+ AddEffectsStreams();
+ Start(1.0f /* playback_rate */);
}
INSTANTIATE_TEST_CASE_P(
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698