Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdint.h> | 5 #include <stdint.h> |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 | 7 |
| 8 #include <algorithm> | |
| 8 #include <limits> | 9 #include <limits> |
| 9 #include <memory> | 10 #include <memory> |
| 10 #include <vector> | 11 #include <vector> |
| 11 | 12 |
| 12 #include "base/bind.h" | 13 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 16 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 17 #include "base/threading/thread_checker.h" | 18 #include "base/threading/thread_checker.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 35 class MultizoneBackendTest; | 36 class MultizoneBackendTest; |
| 36 | 37 |
| 37 namespace { | 38 namespace { |
| 38 | 39 |
| 39 const int64_t kMicrosecondsPerSecond = 1000 * 1000; | 40 const int64_t kMicrosecondsPerSecond = 1000 * 1000; |
| 40 // Total length of test, in microseconds. | 41 // Total length of test, in microseconds. |
| 41 const int64_t kPushTimeUs = 2 * kMicrosecondsPerSecond; | 42 const int64_t kPushTimeUs = 2 * kMicrosecondsPerSecond; |
| 42 const int64_t kStartPts = 0; | 43 const int64_t kStartPts = 0; |
| 43 const int64_t kRenderingDelayGracePeriodUs = 250 * 1000; | 44 const int64_t kRenderingDelayGracePeriodUs = 250 * 1000; |
| 44 const int64_t kMaxRenderingDelayErrorUs = 200; | 45 const int64_t kMaxRenderingDelayErrorUs = 200; |
| 45 const int kNumEffectsStreams = 3; | 46 const int kNumEffectsStreams = 1; |
| 46 | 47 |
| 47 void IgnoreEos() {} | 48 void IgnoreEos() {} |
| 48 | 49 |
| 49 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate { | 50 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate { |
| 50 public: | 51 public: |
| 51 BufferFeeder(const AudioConfig& config, | 52 BufferFeeder(const AudioConfig& config, |
| 52 bool effects_only, | 53 bool effects_only, |
| 53 const base::Closure& eos_cb); | 54 const base::Closure& eos_cb); |
| 54 ~BufferFeeder() override {} | 55 ~BufferFeeder() override {} |
| 55 | 56 |
| 56 void Initialize(); | 57 void Initialize(); |
| 57 void Start(); | 58 void Start(); |
| 58 void Stop(); | 59 void Stop(); |
| 59 | 60 |
| 61 int64_t max_rendering_delay_error_us() { | |
| 62 return max_rendering_delay_error_us_; | |
| 63 } | |
| 64 | |
| 65 int64_t max_positive_rendering_delay_error_us() { | |
| 66 return max_positive_rendering_delay_error_us_; | |
| 67 } | |
| 68 | |
| 69 int64_t max_negative_rendering_delay_error_us() { | |
| 70 return max_negative_rendering_delay_error_us_; | |
| 71 } | |
| 72 | |
| 73 int64_t average_rendering_delay_error_us() { | |
| 74 return average_rendering_delay_error_us_; | |
| 75 } | |
| 76 | |
| 60 private: | 77 private: |
| 61 void FeedBuffer(); | 78 void FeedBuffer(); |
| 62 | 79 |
| 63 // MediaPipelineBackend::Decoder::Delegate implementation: | 80 // MediaPipelineBackend::Decoder::Delegate implementation: |
| 64 void OnPushBufferComplete(MediaPipelineBackend::BufferStatus status) override; | 81 void OnPushBufferComplete(MediaPipelineBackend::BufferStatus status) override; |
| 65 void OnEndOfStream() override; | 82 void OnEndOfStream() override; |
| 66 void OnDecoderError() override { | 83 void OnDecoderError() override { |
| 67 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 68 if (effects_only_) { | 85 if (effects_only_) { |
| 69 feeding_completed_ = true; | 86 feeding_completed_ = true; |
| 70 } else { | 87 } else { |
| 71 ASSERT_TRUE(false); | 88 ASSERT_TRUE(false); |
| 72 } | 89 } |
| 73 } | 90 } |
| 74 void OnKeyStatusChanged(const std::string& key_id, | 91 void OnKeyStatusChanged(const std::string& key_id, |
| 75 CastKeyStatus key_status, | 92 CastKeyStatus key_status, |
| 76 uint32_t system_code) override { | 93 uint32_t system_code) override { |
| 77 DCHECK(thread_checker_.CalledOnValidThread()); | 94 DCHECK(thread_checker_.CalledOnValidThread()); |
| 78 ASSERT_TRUE(false); | 95 ASSERT_TRUE(false); |
| 79 } | 96 } |
| 80 void OnVideoResolutionChanged(const Size& size) override { | 97 void OnVideoResolutionChanged(const Size& size) override { |
| 81 DCHECK(thread_checker_.CalledOnValidThread()); | 98 DCHECK(thread_checker_.CalledOnValidThread()); |
| 82 } | 99 } |
| 83 | 100 |
| 84 const AudioConfig config_; | 101 const AudioConfig config_; |
| 85 const bool effects_only_; | 102 const bool effects_only_; |
| 86 const base::Closure eos_cb_; | 103 const base::Closure eos_cb_; |
| 104 int64_t max_rendering_delay_error_us_; | |
| 105 int64_t max_positive_rendering_delay_error_us_; | |
| 106 int64_t max_negative_rendering_delay_error_us_; | |
| 107 int64_t average_rendering_delay_error_us_; | |
| 108 size_t sample_count_; | |
| 87 bool feeding_completed_; | 109 bool feeding_completed_; |
| 88 std::unique_ptr<TaskRunnerImpl> task_runner_; | 110 std::unique_ptr<TaskRunnerImpl> task_runner_; |
| 89 std::unique_ptr<MediaPipelineBackend> backend_; | 111 std::unique_ptr<MediaPipelineBackend> backend_; |
| 90 MediaPipelineBackend::AudioDecoder* decoder_; | 112 MediaPipelineBackend::AudioDecoder* decoder_; |
| 91 int64_t push_limit_us_; | 113 int64_t push_limit_us_; |
| 92 int64_t last_push_length_us_; | 114 int64_t last_push_length_us_; |
| 93 int64_t pushed_us_; | 115 int64_t pushed_us_; |
| 94 int64_t next_push_playback_timestamp_; | 116 int64_t next_push_playback_timestamp_; |
| 95 scoped_refptr<DecoderBufferBase> pending_buffer_; | 117 scoped_refptr<DecoderBufferBase> pending_buffer_; |
| 96 base::ThreadChecker thread_checker_; | 118 base::ThreadChecker thread_checker_; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 }; | 153 }; |
| 132 | 154 |
| 133 namespace { | 155 namespace { |
| 134 | 156 |
| 135 BufferFeeder::BufferFeeder(const AudioConfig& config, | 157 BufferFeeder::BufferFeeder(const AudioConfig& config, |
| 136 bool effects_only, | 158 bool effects_only, |
| 137 const base::Closure& eos_cb) | 159 const base::Closure& eos_cb) |
| 138 : config_(config), | 160 : config_(config), |
| 139 effects_only_(effects_only), | 161 effects_only_(effects_only), |
| 140 eos_cb_(eos_cb), | 162 eos_cb_(eos_cb), |
| 163 max_rendering_delay_error_us_(0), | |
| 164 max_positive_rendering_delay_error_us_(0), | |
| 165 max_negative_rendering_delay_error_us_(0), | |
| 166 average_rendering_delay_error_us_(0), | |
| 167 sample_count_(0), | |
| 141 feeding_completed_(false), | 168 feeding_completed_(false), |
| 142 task_runner_(new TaskRunnerImpl()), | 169 task_runner_(new TaskRunnerImpl()), |
| 143 decoder_(nullptr), | 170 decoder_(nullptr), |
| 144 push_limit_us_(effects_only_ ? 0 : kPushTimeUs), | 171 push_limit_us_(effects_only_ ? 0 : kPushTimeUs), |
| 145 last_push_length_us_(0), | 172 last_push_length_us_(0), |
| 146 pushed_us_(0), | 173 pushed_us_(0), |
| 147 next_push_playback_timestamp_(0) { | 174 next_push_playback_timestamp_(0) { |
| 148 CHECK(!eos_cb_.is_null()); | 175 CHECK(!eos_cb_.is_null()); |
| 149 } | 176 } |
| 150 | 177 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 decoder_->GetRenderingDelay(); | 248 decoder_->GetRenderingDelay(); |
| 222 int64_t expected_next_push_playback_timestamp = | 249 int64_t expected_next_push_playback_timestamp = |
| 223 next_push_playback_timestamp_ + last_push_length_us_; | 250 next_push_playback_timestamp_ + last_push_length_us_; |
| 224 next_push_playback_timestamp_ = | 251 next_push_playback_timestamp_ = |
| 225 delay.timestamp_microseconds + delay.delay_microseconds; | 252 delay.timestamp_microseconds + delay.delay_microseconds; |
| 226 // Check rendering delay accuracy only if we have pushed more than | 253 // Check rendering delay accuracy only if we have pushed more than |
| 227 // kRenderingDelayGracePeriodUs of data. | 254 // kRenderingDelayGracePeriodUs of data. |
| 228 if (pushed_us_ > kRenderingDelayGracePeriodUs) { | 255 if (pushed_us_ > kRenderingDelayGracePeriodUs) { |
| 229 int64_t error = | 256 int64_t error = |
| 230 next_push_playback_timestamp_ - expected_next_push_playback_timestamp; | 257 next_push_playback_timestamp_ - expected_next_push_playback_timestamp; |
| 231 EXPECT_LT(std::abs(error), kMaxRenderingDelayErrorUs) | 258 max_rendering_delay_error_us_ = |
| 232 << "Bad rendering delay after " << pushed_us_ << " us"; | 259 std::max(max_rendering_delay_error_us_, std::abs(error)); |
| 260 average_rendering_delay_error_us_ = | |
|
kmackay
2016/06/15 20:26:48
Seems like it would be more accurate to maintain t
jameswest
2016/06/15 21:41:00
Done.
| |
| 261 (average_rendering_delay_error_us_ * sample_count_ + | |
| 262 std::abs(error)) / | |
| 263 (sample_count_ + 1); | |
| 264 if (error >= 0) { | |
| 265 max_positive_rendering_delay_error_us_ = | |
| 266 std::max(max_positive_rendering_delay_error_us_, error); | |
| 267 } else { | |
| 268 max_negative_rendering_delay_error_us_ = | |
| 269 std::min(max_negative_rendering_delay_error_us_, error); | |
| 270 } | |
| 271 sample_count_++; | |
| 233 } | 272 } |
| 234 } | 273 } |
| 235 pushed_us_ += last_push_length_us_; | 274 pushed_us_ += last_push_length_us_; |
| 236 | 275 |
| 237 if (feeding_completed_) | 276 if (feeding_completed_) |
| 238 return; | 277 return; |
| 239 | 278 |
| 240 base::ThreadTaskRunnerHandle::Get()->PostTask( | 279 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 241 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); | 280 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); |
| 242 } | 281 } |
| 243 | 282 |
| 244 } // namespace | 283 } // namespace |
| 245 | 284 |
| 246 MultizoneBackendTest::MultizoneBackendTest() {} | 285 MultizoneBackendTest::MultizoneBackendTest() {} |
| 247 | 286 |
| 248 MultizoneBackendTest::~MultizoneBackendTest() {} | 287 MultizoneBackendTest::~MultizoneBackendTest() {} |
| 249 | 288 |
| 250 void MultizoneBackendTest::Initialize(int sample_rate) { | 289 void MultizoneBackendTest::Initialize(int sample_rate) { |
| 251 AudioConfig config; | 290 AudioConfig config; |
| 252 config.codec = kCodecPCM; | 291 config.codec = kCodecPCM; |
| 253 config.sample_format = kSampleFormatPlanarF32; | 292 config.sample_format = kSampleFormatS32; |
| 254 config.channel_number = 2; | 293 config.channel_number = 2; |
| 255 config.bytes_per_channel = 4; | 294 config.bytes_per_channel = 4; |
| 256 config.samples_per_second = sample_rate; | 295 config.samples_per_second = sample_rate; |
| 257 | 296 |
| 258 audio_feeder_.reset( | 297 audio_feeder_.reset( |
| 259 new BufferFeeder(config, false /* effects_only */, | 298 new BufferFeeder(config, false /* effects_only */, |
| 260 base::Bind(&MultizoneBackendTest::OnEndOfStream, | 299 base::Bind(&MultizoneBackendTest::OnEndOfStream, |
| 261 base::Unretained(this)))); | 300 base::Unretained(this)))); |
| 262 audio_feeder_->Initialize(); | 301 audio_feeder_->Initialize(); |
| 263 } | 302 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 284 CHECK(audio_feeder_); | 323 CHECK(audio_feeder_); |
| 285 audio_feeder_->Start(); | 324 audio_feeder_->Start(); |
| 286 } | 325 } |
| 287 | 326 |
| 288 void MultizoneBackendTest::OnEndOfStream() { | 327 void MultizoneBackendTest::OnEndOfStream() { |
| 289 audio_feeder_->Stop(); | 328 audio_feeder_->Stop(); |
| 290 for (auto& feeder : effects_feeders_) | 329 for (auto& feeder : effects_feeders_) |
| 291 feeder->Stop(); | 330 feeder->Stop(); |
| 292 | 331 |
| 293 base::MessageLoop::current()->QuitWhenIdle(); | 332 base::MessageLoop::current()->QuitWhenIdle(); |
| 333 | |
| 334 EXPECT_LT(audio_feeder_->max_rendering_delay_error_us(), | |
| 335 kMaxRenderingDelayErrorUs) | |
| 336 << "Max positive rendering delay error: " | |
| 337 << audio_feeder_->max_positive_rendering_delay_error_us() | |
| 338 << "\nMax negative rendering delay error: " | |
| 339 << audio_feeder_->max_negative_rendering_delay_error_us() | |
| 340 << "\nAverage rendering delay error: " | |
| 341 << audio_feeder_->average_rendering_delay_error_us(); | |
| 294 } | 342 } |
| 295 | 343 |
| 296 TEST_P(MultizoneBackendTest, RenderingDelay) { | 344 TEST_P(MultizoneBackendTest, RenderingDelay) { |
| 297 std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); | 345 std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); |
| 298 | 346 |
| 299 Initialize(GetParam()); | 347 Initialize(GetParam()); |
| 300 AddEffectsStreams(); | 348 AddEffectsStreams(); |
| 301 Start(); | 349 Start(); |
| 302 message_loop->Run(); | 350 message_loop->Run(); |
| 303 } | 351 } |
| 304 | 352 |
| 305 INSTANTIATE_TEST_CASE_P(Required, | 353 INSTANTIATE_TEST_CASE_P(Required, |
| 306 MultizoneBackendTest, | 354 MultizoneBackendTest, |
| 307 ::testing::Values(8000, | 355 ::testing::Values(8000, |
| 308 11025, | 356 11025, |
| 309 12000, | 357 12000, |
| 310 16000, | 358 16000, |
| 311 22050, | 359 22050, |
| 312 24000, | 360 24000, |
| 313 32000, | 361 32000, |
| 314 44100, | 362 44100, |
| 315 48000)); | 363 48000)); |
| 316 | 364 |
| 317 INSTANTIATE_TEST_CASE_P(Optional, | 365 INSTANTIATE_TEST_CASE_P(Optional, |
| 318 MultizoneBackendTest, | 366 MultizoneBackendTest, |
| 319 ::testing::Values(64000, 88200, 96000)); | 367 ::testing::Values(64000, 88200, 96000)); |
| 320 | 368 |
| 321 } // namespace media | 369 } // namespace media |
| 322 } // namespace chromecast | 370 } // namespace chromecast |
| OLD | NEW |