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 <algorithm> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | |
| 14 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 15 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/ptr_util.h" | |
| 16 #include "base/memory/ref_counted.h" | 18 #include "base/memory/ref_counted.h" |
| 17 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
| 18 #include "base/run_loop.h" | 20 #include "base/run_loop.h" |
| 19 #include "base/threading/thread_checker.h" | 21 #include "base/threading/thread_checker.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
| 21 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 22 #include "chromecast/base/task_runner_impl.h" | 24 #include "chromecast/base/task_runner_impl.h" |
| 23 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" | 25 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" |
| 24 #include "chromecast/media/cma/base/decoder_config_adapter.h" | 26 #include "chromecast/media/cma/base/decoder_config_adapter.h" |
| 25 #include "chromecast/public/cast_media_shlib.h" | 27 #include "chromecast/public/cast_media_shlib.h" |
| 26 #include "chromecast/public/media/cast_decoder_buffer.h" | 28 #include "chromecast/public/media/cast_decoder_buffer.h" |
| 27 #include "chromecast/public/media/decoder_config.h" | 29 #include "chromecast/public/media/decoder_config.h" |
| 28 #include "chromecast/public/media/media_pipeline_backend.h" | 30 #include "chromecast/public/media/media_pipeline_backend.h" |
| 29 #include "chromecast/public/media/media_pipeline_device_params.h" | 31 #include "chromecast/public/media/media_pipeline_device_params.h" |
| 30 #include "chromecast/public/volume_control.h" | 32 #include "chromecast/public/volume_control.h" |
| 31 #include "media/audio/audio_device_description.h" | 33 #include "media/audio/audio_device_description.h" |
| 32 #include "media/base/audio_decoder_config.h" | 34 #include "media/base/audio_decoder_config.h" |
| 33 #include "media/base/decoder_buffer.h" | 35 #include "media/base/decoder_buffer.h" |
| 34 #include "testing/gtest/include/gtest/gtest.h" | 36 #include "testing/gtest/include/gtest/gtest.h" |
| 35 | 37 |
| 36 namespace chromecast { | 38 namespace chromecast { |
| 37 namespace media { | 39 namespace media { |
| 38 | 40 |
| 39 class MultizoneBackendTest; | 41 class MultizoneBackendTest; |
| 40 | 42 |
| 41 namespace { | 43 namespace { |
| 42 | 44 |
| 43 const int64_t kMicrosecondsPerSecond = 1000 * 1000; | |
| 44 // Total length of test, in microseconds. | 45 // Total length of test, in microseconds. |
| 45 const int64_t kPushTimeUs = 2 * kMicrosecondsPerSecond; | 46 const int64_t kPushTimeUs = 2.0 * base::Time::kMicrosecondsPerSecond; |
|
kmackay
2017/05/27 04:13:56
Why 2.0 (instead of just 2)?
jameswest
2017/05/30 21:25:52
I changed it to 0.5 while testing and changed it b
| |
| 46 const int64_t kStartPts = 0; | 47 const int64_t kStartPts = 0; |
| 47 const int64_t kMaxRenderingDelayErrorUs = 200; | 48 const int64_t kMaxRenderingDelayErrorUs = 200; |
| 48 const int kNumEffectsStreams = 1; | 49 const int kNumEffectsStreams = 1; |
| 49 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); | 50 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); |
| 50 | 51 |
| 51 void IgnoreEos() {} | 52 void IgnoreEos() {} |
| 52 | 53 |
| 53 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate { | 54 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate { |
| 54 public: | 55 public: |
| 55 BufferFeeder(const AudioConfig& config, | 56 BufferFeeder(const AudioConfig& config, |
| 56 bool effects_only, | 57 bool effects_only, |
| 57 const base::Closure& eos_cb); | 58 base::OnceClosure eos_cb, |
| 59 int playback_rate_change_count); | |
| 58 ~BufferFeeder() override {} | 60 ~BufferFeeder() override {} |
| 59 | 61 |
| 60 void Initialize(float playback_rate); | 62 void Initialize(); |
| 61 void Start(); | 63 void Start(float playback_rate); |
| 62 void Stop(); | 64 void Stop(); |
| 63 | 65 |
| 64 int64_t max_rendering_delay_error_us() { | 66 int64_t GetMaxRenderingDelayErrorUs() { |
| 65 return max_rendering_delay_error_us_; | 67 int64_t max = 0; |
| 66 } | 68 for (int64_t error : errors_) { |
| 67 | 69 if (error == kNoTimestamp) { |
| 68 int64_t max_positive_rendering_delay_error_us() { | 70 continue; |
| 69 return max_positive_rendering_delay_error_us_; | 71 } |
| 70 } | 72 max = std::max(max, std::abs(error)); |
| 71 | 73 } |
| 72 int64_t max_negative_rendering_delay_error_us() { | 74 return max; |
| 73 return max_negative_rendering_delay_error_us_; | |
| 74 } | |
| 75 | |
| 76 int64_t average_rendering_delay_error_us() { | |
| 77 return total_rendering_delay_error_us_ / sample_count_; | |
| 78 } | 75 } |
| 79 | 76 |
| 80 private: | 77 private: |
| 81 void FeedBuffer(); | 78 void FeedBuffer(); |
| 82 | 79 |
| 83 // MediaPipelineBackend::Decoder::Delegate implementation: | 80 // MediaPipelineBackend::Decoder::Delegate implementation: |
| 84 void OnPushBufferComplete(MediaPipelineBackend::BufferStatus status) override; | 81 void OnPushBufferComplete(MediaPipelineBackend::BufferStatus status) override; |
| 85 void OnEndOfStream() override; | 82 void OnEndOfStream() override; |
| 86 void OnDecoderError() override { | 83 void OnDecoderError() override { |
| 87 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 88 if (effects_only_) { | 85 if (effects_only_) { |
| 89 feeding_completed_ = true; | 86 feeding_completed_ = true; |
| 90 } else { | 87 } else { |
| 91 ASSERT_TRUE(false); | 88 ASSERT_TRUE(false); |
| 92 } | 89 } |
| 93 } | 90 } |
| 94 void OnKeyStatusChanged(const std::string& key_id, | 91 void OnKeyStatusChanged(const std::string& key_id, |
| 95 CastKeyStatus key_status, | 92 CastKeyStatus key_status, |
| 96 uint32_t system_code) override { | 93 uint32_t system_code) override { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); | 94 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 ASSERT_TRUE(false); | 95 ASSERT_TRUE(false); |
| 99 } | 96 } |
| 100 void OnVideoResolutionChanged(const Size& size) override { | 97 void OnVideoResolutionChanged(const Size& size) override { |
| 101 DCHECK(thread_checker_.CalledOnValidThread()); | 98 DCHECK(thread_checker_.CalledOnValidThread()); |
| 102 } | 99 } |
| 103 | 100 |
| 104 const AudioConfig config_; | 101 const AudioConfig config_; |
| 105 const bool effects_only_; | 102 const bool effects_only_; |
| 106 const base::Closure eos_cb_; | 103 base::OnceClosure eos_cb_; |
| 107 double original_playback_rate_; | 104 const int64_t push_limit_us_; |
| 108 double playback_rate_; | 105 const int64_t playback_rate_change_interval_us_; |
| 109 int64_t max_rendering_delay_error_us_; | 106 float original_playback_rate_; |
| 110 int64_t max_positive_rendering_delay_error_us_; | 107 float playback_rate_; |
| 111 int64_t max_negative_rendering_delay_error_us_; | 108 std::vector<int64_t> errors_; |
| 112 int64_t total_rendering_delay_error_us_; | |
| 113 size_t sample_count_; | |
| 114 bool feeding_completed_; | 109 bool feeding_completed_; |
| 115 std::unique_ptr<TaskRunnerImpl> task_runner_; | 110 TaskRunnerImpl task_runner_; |
| 116 std::unique_ptr<MediaPipelineBackend> backend_; | 111 std::unique_ptr<MediaPipelineBackend> backend_; |
| 117 MediaPipelineBackend::AudioDecoder* decoder_; | 112 MediaPipelineBackend::AudioDecoder* decoder_; |
| 118 int64_t push_limit_us_; | |
| 119 int64_t last_push_length_us_; | 113 int64_t last_push_length_us_; |
| 120 int64_t pushed_us_; | 114 int64_t pushed_us_; |
| 115 int64_t pushed_us_when_rate_changed_; | |
| 121 int64_t next_push_playback_timestamp_; | 116 int64_t next_push_playback_timestamp_; |
| 122 scoped_refptr<DecoderBufferBase> pending_buffer_; | 117 scoped_refptr<DecoderBufferBase> pending_buffer_; |
| 123 base::ThreadChecker thread_checker_; | 118 base::ThreadChecker thread_checker_; |
| 124 | 119 |
| 125 DISALLOW_COPY_AND_ASSIGN(BufferFeeder); | 120 DISALLOW_COPY_AND_ASSIGN(BufferFeeder); |
| 126 }; | 121 }; |
| 127 | 122 |
| 128 } // namespace | 123 } // namespace |
| 129 | 124 |
| 130 using TestParams = std::tr1::tuple<int, // sample rate | 125 using TestParams = |
| 131 float>; // playback rate | 126 std::tr1::tuple<int /* sample rate */, float /* playback rate */>; |
| 132 | 127 |
| 133 class MultizoneBackendTest : public testing::TestWithParam<TestParams> { | 128 class MultizoneBackendTest : public testing::TestWithParam<TestParams> { |
| 134 public: | 129 public: |
| 135 MultizoneBackendTest(); | 130 MultizoneBackendTest(); |
| 136 ~MultizoneBackendTest() override; | 131 ~MultizoneBackendTest() override; |
| 137 | 132 |
| 138 void SetUp() override { | 133 void SetUp() override { |
| 139 srand(12345); | 134 srand(12345); |
| 140 CastMediaShlib::Initialize(base::CommandLine::ForCurrentProcess()->argv()); | 135 CastMediaShlib::Initialize(base::CommandLine::ForCurrentProcess()->argv()); |
| 141 if (VolumeControl::Initialize) { | 136 if (VolumeControl::Initialize) { |
| 142 VolumeControl::Initialize(base::CommandLine::ForCurrentProcess()->argv()); | 137 VolumeControl::Initialize(base::CommandLine::ForCurrentProcess()->argv()); |
| 143 } | 138 } |
| 144 } | 139 } |
| 145 | 140 |
| 146 void TearDown() override { | 141 void TearDown() override { |
| 147 // Pipeline must be destroyed before finalizing media shlib. | 142 // Pipeline must be destroyed before finalizing media shlib. |
| 148 audio_feeder_.reset(); | 143 audio_feeder_.reset(); |
| 149 effects_feeders_.clear(); | 144 effects_feeders_.clear(); |
| 150 if (VolumeControl::Finalize) { | 145 if (VolumeControl::Finalize) { |
| 151 VolumeControl::Finalize(); | 146 VolumeControl::Finalize(); |
| 152 } | 147 } |
| 153 CastMediaShlib::Finalize(); | 148 CastMediaShlib::Finalize(); |
| 154 } | 149 } |
| 155 | 150 |
| 156 void AddEffectsStreams(); | 151 void AddEffectsStreams(); |
| 157 | 152 |
| 158 void Initialize(int sample_rate, float playback_rate); | 153 void Initialize(int sample_rate, int playback_rate_change_count); |
| 159 void Start(); | 154 void Start(float playback_rate); |
| 160 void OnEndOfStream(); | 155 void OnEndOfStream(); |
| 161 | 156 |
| 162 private: | 157 private: |
| 158 base::MessageLoop message_loop_; | |
| 163 std::vector<std::unique_ptr<BufferFeeder>> effects_feeders_; | 159 std::vector<std::unique_ptr<BufferFeeder>> effects_feeders_; |
| 164 std::unique_ptr<BufferFeeder> audio_feeder_; | 160 std::unique_ptr<BufferFeeder> audio_feeder_; |
| 165 | 161 |
| 166 DISALLOW_COPY_AND_ASSIGN(MultizoneBackendTest); | 162 DISALLOW_COPY_AND_ASSIGN(MultizoneBackendTest); |
| 167 }; | 163 }; |
| 168 | 164 |
| 169 namespace { | 165 namespace { |
| 170 | 166 |
| 171 BufferFeeder::BufferFeeder(const AudioConfig& config, | 167 BufferFeeder::BufferFeeder(const AudioConfig& config, |
| 172 bool effects_only, | 168 bool effects_only, |
| 173 const base::Closure& eos_cb) | 169 base::OnceClosure eos_cb, |
| 170 int playback_rate_change_count) | |
| 174 : config_(config), | 171 : config_(config), |
| 175 effects_only_(effects_only), | 172 effects_only_(effects_only), |
| 176 eos_cb_(eos_cb), | 173 eos_cb_(std::move(eos_cb)), |
| 177 original_playback_rate_(1.0), | 174 push_limit_us_(effects_only_ ? 0 : kPushTimeUs), |
| 178 playback_rate_(1.0), | 175 playback_rate_change_interval_us_(push_limit_us_ / |
| 179 max_rendering_delay_error_us_(0), | 176 (playback_rate_change_count + 1)), |
| 180 max_positive_rendering_delay_error_us_(0), | 177 original_playback_rate_(1.0f), |
| 181 max_negative_rendering_delay_error_us_(0), | 178 playback_rate_(1.0f), |
| 182 total_rendering_delay_error_us_(0), | |
| 183 sample_count_(0), | |
| 184 feeding_completed_(false), | 179 feeding_completed_(false), |
| 185 task_runner_(new TaskRunnerImpl()), | |
| 186 decoder_(nullptr), | 180 decoder_(nullptr), |
| 187 push_limit_us_(effects_only_ ? 0 : kPushTimeUs), | |
| 188 last_push_length_us_(0), | 181 last_push_length_us_(0), |
| 189 pushed_us_(0), | 182 pushed_us_(0), |
| 183 pushed_us_when_rate_changed_(0), | |
| 190 next_push_playback_timestamp_(kNoTimestamp) { | 184 next_push_playback_timestamp_(kNoTimestamp) { |
| 191 CHECK(!eos_cb_.is_null()); | 185 CHECK(eos_cb_); |
| 192 } | 186 } |
| 193 | 187 |
| 194 void BufferFeeder::Initialize(float playback_rate) { | 188 void BufferFeeder::Initialize() { |
| 195 original_playback_rate_ = playback_rate_ = playback_rate; | |
| 196 MediaPipelineDeviceParams params( | 189 MediaPipelineDeviceParams params( |
| 197 MediaPipelineDeviceParams::kModeIgnorePts, | 190 MediaPipelineDeviceParams::kModeIgnorePts, |
| 198 effects_only_ ? MediaPipelineDeviceParams::kAudioStreamSoundEffects | 191 effects_only_ ? MediaPipelineDeviceParams::kAudioStreamSoundEffects |
| 199 : MediaPipelineDeviceParams::kAudioStreamNormal, | 192 : MediaPipelineDeviceParams::kAudioStreamNormal, |
| 200 task_runner_.get(), AudioContentType::kMedia, | 193 &task_runner_, AudioContentType::kMedia, |
| 201 ::media::AudioDeviceDescription::kDefaultDeviceId); | 194 ::media::AudioDeviceDescription::kDefaultDeviceId); |
| 202 backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params)); | 195 backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params)); |
| 203 CHECK(backend_); | 196 CHECK(backend_); |
| 204 | 197 |
| 205 decoder_ = backend_->CreateAudioDecoder(); | 198 decoder_ = backend_->CreateAudioDecoder(); |
| 206 CHECK(decoder_); | 199 CHECK(decoder_); |
| 207 ASSERT_TRUE(decoder_->SetConfig(config_)); | 200 ASSERT_TRUE(decoder_->SetConfig(config_)); |
| 208 decoder_->SetDelegate(this); | 201 decoder_->SetDelegate(this); |
| 209 | 202 |
| 210 ASSERT_TRUE(backend_->Initialize()); | 203 ASSERT_TRUE(backend_->Initialize()); |
| 211 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate)); | |
| 212 } | 204 } |
| 213 | 205 |
| 214 void BufferFeeder::Start() { | 206 void BufferFeeder::Start(float playback_rate) { |
| 207 // AMP devices only support playback rates between 0.5 and 2.0. | |
| 208 ASSERT_GE(playback_rate, 0.5f); | |
| 209 ASSERT_LE(playback_rate, 2.0f); | |
| 210 original_playback_rate_ = playback_rate_ = playback_rate; | |
| 215 ASSERT_TRUE(backend_->Start(kStartPts)); | 211 ASSERT_TRUE(backend_->Start(kStartPts)); |
| 212 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate)); | |
| 216 base::ThreadTaskRunnerHandle::Get()->PostTask( | 213 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 217 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); | 214 FROM_HERE, |
| 215 base::BindOnce(&BufferFeeder::FeedBuffer, base::Unretained(this))); | |
| 218 } | 216 } |
| 219 | 217 |
| 220 void BufferFeeder::Stop() { | 218 void BufferFeeder::Stop() { |
| 221 feeding_completed_ = true; | 219 feeding_completed_ = true; |
| 222 backend_->Stop(); | 220 backend_->Stop(); |
| 223 } | 221 } |
| 224 | 222 |
| 225 void BufferFeeder::FeedBuffer() { | 223 void BufferFeeder::FeedBuffer() { |
| 226 CHECK(decoder_); | 224 CHECK(decoder_); |
| 227 if (feeding_completed_) | 225 if (feeding_completed_) |
| 228 return; | 226 return; |
| 229 | 227 |
| 230 if (!effects_only_ && pushed_us_ >= push_limit_us_ / 2 && | 228 if (!effects_only_ && pushed_us_ > pushed_us_when_rate_changed_ + |
| 231 playback_rate_ == original_playback_rate_) { | 229 playback_rate_change_interval_us_) { |
| 232 if (original_playback_rate_ < 1.0) { | 230 pushed_us_when_rate_changed_ = pushed_us_; |
| 231 if (playback_rate_ != original_playback_rate_) { | |
| 232 playback_rate_ = original_playback_rate_; | |
| 233 } else if (original_playback_rate_ < 1.0) { | |
| 233 playback_rate_ = original_playback_rate_ * 2; | 234 playback_rate_ = original_playback_rate_ * 2; |
| 234 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_)); | |
| 235 } else { | 235 } else { |
| 236 playback_rate_ = original_playback_rate_ / 2; | 236 playback_rate_ = original_playback_rate_ / 2; |
| 237 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_)); | |
| 238 } | 237 } |
| 238 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_)); | |
| 239 // Changing the playback rate will change the rendering delay on devices | |
| 240 // where playback rate changes apply to audio that has already been pushed. | |
| 241 // Ignore the next rendering delay. | |
| 242 next_push_playback_timestamp_ = kNoTimestamp; | |
| 239 } | 243 } |
| 240 | 244 |
| 241 if (!effects_only_ && pushed_us_ >= push_limit_us_) { | 245 if (!effects_only_ && pushed_us_ >= push_limit_us_) { |
| 242 pending_buffer_ = new media::DecoderBufferAdapter( | 246 pending_buffer_ = new media::DecoderBufferAdapter( |
| 243 ::media::DecoderBuffer::CreateEOSBuffer()); | 247 ::media::DecoderBuffer::CreateEOSBuffer()); |
| 244 feeding_completed_ = true; | 248 feeding_completed_ = true; |
| 245 last_push_length_us_ = 0; | 249 last_push_length_us_ = 0; |
| 246 } else { | 250 } else { |
| 247 int size_bytes = (rand() % 96 + 32) * 16; | 251 int size_bytes = (rand() % 96 + 32) * 16; |
| 248 int num_samples = | 252 int num_samples = |
| 249 size_bytes / (config_.bytes_per_channel * config_.channel_number); | 253 size_bytes / (config_.bytes_per_channel * config_.channel_number); |
| 250 last_push_length_us_ = num_samples * kMicrosecondsPerSecond / | 254 last_push_length_us_ = num_samples * base::Time::kMicrosecondsPerSecond / |
| 251 (config_.samples_per_second * playback_rate_); | 255 (config_.samples_per_second * playback_rate_); |
| 252 scoped_refptr<::media::DecoderBuffer> silence_buffer( | 256 scoped_refptr<::media::DecoderBuffer> silence_buffer( |
| 253 new ::media::DecoderBuffer(size_bytes)); | 257 new ::media::DecoderBuffer(size_bytes)); |
| 254 memset(silence_buffer->writable_data(), 0, silence_buffer->data_size()); | 258 memset(silence_buffer->writable_data(), 0, silence_buffer->data_size()); |
| 255 pending_buffer_ = new media::DecoderBufferAdapter(silence_buffer); | 259 pending_buffer_ = new media::DecoderBufferAdapter(silence_buffer); |
| 256 pending_buffer_->set_timestamp( | 260 pending_buffer_->set_timestamp( |
| 257 base::TimeDelta::FromMicroseconds(pushed_us_)); | 261 base::TimeDelta::FromMicroseconds(pushed_us_)); |
| 258 } | 262 } |
| 259 BufferStatus status = decoder_->PushBuffer(pending_buffer_.get()); | 263 BufferStatus status = decoder_->PushBuffer(pending_buffer_.get()); |
| 260 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed); | 264 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed); |
| 261 if (status == MediaPipelineBackend::kBufferPending) | 265 if (status == MediaPipelineBackend::kBufferPending) |
| 262 return; | 266 return; |
| 263 OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess); | 267 OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess); |
| 264 } | 268 } |
| 265 | 269 |
| 266 void BufferFeeder::OnEndOfStream() { | 270 void BufferFeeder::OnEndOfStream() { |
| 267 DCHECK(thread_checker_.CalledOnValidThread()); | 271 DCHECK(thread_checker_.CalledOnValidThread()); |
| 268 eos_cb_.Run(); | 272 std::move(eos_cb_).Run(); |
| 269 } | 273 } |
| 270 | 274 |
| 271 void BufferFeeder::OnPushBufferComplete(BufferStatus status) { | 275 void BufferFeeder::OnPushBufferComplete(BufferStatus status) { |
| 272 DCHECK(thread_checker_.CalledOnValidThread()); | 276 DCHECK(thread_checker_.CalledOnValidThread()); |
| 273 pending_buffer_ = nullptr; | 277 pending_buffer_ = nullptr; |
| 274 | 278 |
| 275 if (!effects_only_) { | 279 if (!effects_only_) { |
| 276 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed); | 280 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed); |
| 277 MediaPipelineBackend::AudioDecoder::RenderingDelay delay = | 281 MediaPipelineBackend::AudioDecoder::RenderingDelay delay = |
| 278 decoder_->GetRenderingDelay(); | 282 decoder_->GetRenderingDelay(); |
| 279 | 283 |
| 284 int64_t error = kNoTimestamp; | |
| 280 if (delay.timestamp_microseconds == kNoTimestamp) { | 285 if (delay.timestamp_microseconds == kNoTimestamp) { |
| 281 next_push_playback_timestamp_ = kNoTimestamp; | 286 next_push_playback_timestamp_ = kNoTimestamp; |
| 282 } else { | 287 } else { |
| 283 if (next_push_playback_timestamp_ == kNoTimestamp) { | 288 if (next_push_playback_timestamp_ == kNoTimestamp) { |
| 284 next_push_playback_timestamp_ = | 289 next_push_playback_timestamp_ = |
| 285 delay.timestamp_microseconds + delay.delay_microseconds; | 290 delay.timestamp_microseconds + delay.delay_microseconds; |
| 286 } else { | 291 } else { |
| 287 int64_t expected_next_push_playback_timestamp = | 292 int64_t expected_next_push_playback_timestamp = |
| 288 next_push_playback_timestamp_ + last_push_length_us_; | 293 next_push_playback_timestamp_ + last_push_length_us_; |
| 289 next_push_playback_timestamp_ = | 294 next_push_playback_timestamp_ = |
| 290 delay.timestamp_microseconds + delay.delay_microseconds; | 295 delay.timestamp_microseconds + delay.delay_microseconds; |
| 291 int64_t error = next_push_playback_timestamp_ - | 296 error = next_push_playback_timestamp_ - |
| 292 expected_next_push_playback_timestamp; | 297 expected_next_push_playback_timestamp; |
| 293 | |
| 294 max_rendering_delay_error_us_ = | |
| 295 std::max(max_rendering_delay_error_us_, std::abs(error)); | |
| 296 total_rendering_delay_error_us_ += std::abs(error); | |
| 297 if (error >= 0) { | |
| 298 max_positive_rendering_delay_error_us_ = | |
| 299 std::max(max_positive_rendering_delay_error_us_, error); | |
| 300 } else { | |
| 301 max_negative_rendering_delay_error_us_ = | |
| 302 std::min(max_negative_rendering_delay_error_us_, error); | |
| 303 } | |
| 304 sample_count_++; | |
| 305 } | 298 } |
| 306 } | 299 } |
| 300 errors_.push_back(error); | |
| 307 } | 301 } |
| 308 pushed_us_ += last_push_length_us_; | 302 pushed_us_ += last_push_length_us_; |
| 309 | 303 |
| 310 if (feeding_completed_) | 304 if (feeding_completed_) |
| 311 return; | 305 return; |
| 312 | 306 |
| 313 base::ThreadTaskRunnerHandle::Get()->PostTask( | 307 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 314 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); | 308 FROM_HERE, |
| 309 base::BindOnce(&BufferFeeder::FeedBuffer, base::Unretained(this))); | |
| 315 } | 310 } |
| 316 | 311 |
| 317 } // namespace | 312 } // namespace |
| 318 | 313 |
| 319 MultizoneBackendTest::MultizoneBackendTest() {} | 314 MultizoneBackendTest::MultizoneBackendTest() {} |
| 320 | 315 |
| 321 MultizoneBackendTest::~MultizoneBackendTest() {} | 316 MultizoneBackendTest::~MultizoneBackendTest() {} |
| 322 | 317 |
| 323 void MultizoneBackendTest::Initialize(int sample_rate, float playback_rate) { | 318 void MultizoneBackendTest::Initialize(int sample_rate, |
| 319 int playback_rate_change_count) { | |
| 324 AudioConfig config; | 320 AudioConfig config; |
| 325 config.codec = kCodecPCM; | 321 config.codec = kCodecPCM; |
| 326 config.sample_format = kSampleFormatS32; | 322 config.sample_format = kSampleFormatPlanarF32; |
|
kmackay
2017/05/27 04:13:56
What was the reason for changing the sample format
jameswest
2017/05/30 21:25:52
I changed it to kSampleFormatS32 in https://codere
| |
| 327 config.channel_number = 2; | 323 config.channel_number = 2; |
| 328 config.bytes_per_channel = 4; | 324 config.bytes_per_channel = 4; |
| 329 config.samples_per_second = sample_rate; | 325 config.samples_per_second = sample_rate; |
| 330 | 326 |
| 331 audio_feeder_.reset( | 327 audio_feeder_ = base::MakeUnique<BufferFeeder>( |
| 332 new BufferFeeder(config, false /* effects_only */, | 328 config, false /* effects_only */, |
| 333 base::Bind(&MultizoneBackendTest::OnEndOfStream, | 329 base::BindOnce(&MultizoneBackendTest::OnEndOfStream, |
| 334 base::Unretained(this)))); | 330 base::Unretained(this)), |
| 335 audio_feeder_->Initialize(playback_rate); | 331 playback_rate_change_count); |
| 332 audio_feeder_->Initialize(); | |
| 336 } | 333 } |
| 337 | 334 |
| 338 void MultizoneBackendTest::AddEffectsStreams() { | 335 void MultizoneBackendTest::AddEffectsStreams() { |
| 339 AudioConfig effects_config; | 336 AudioConfig effects_config; |
| 340 effects_config.codec = kCodecPCM; | 337 effects_config.codec = kCodecPCM; |
| 341 effects_config.sample_format = kSampleFormatS16; | 338 effects_config.sample_format = kSampleFormatS16; |
| 342 effects_config.channel_number = 2; | 339 effects_config.channel_number = 2; |
| 343 effects_config.bytes_per_channel = 2; | 340 effects_config.bytes_per_channel = 2; |
| 344 effects_config.samples_per_second = 48000; | 341 effects_config.samples_per_second = 48000; |
| 345 | 342 |
| 346 for (int i = 0; i < kNumEffectsStreams; ++i) { | 343 for (int i = 0; i < kNumEffectsStreams; ++i) { |
| 347 std::unique_ptr<BufferFeeder> feeder(new BufferFeeder( | 344 auto feeder = base::MakeUnique<BufferFeeder>( |
| 348 effects_config, true /* effects_only */, base::Bind(&IgnoreEos))); | 345 effects_config, true /* effects_only */, base::BindOnce(&IgnoreEos), 0); |
| 349 feeder->Initialize(1.0f); | 346 feeder->Initialize(); |
| 350 effects_feeders_.push_back(std::move(feeder)); | 347 effects_feeders_.push_back(std::move(feeder)); |
| 351 } | 348 } |
| 352 } | 349 } |
| 353 | 350 |
| 354 void MultizoneBackendTest::Start() { | 351 void MultizoneBackendTest::Start(float playback_rate) { |
| 355 for (auto& feeder : effects_feeders_) | 352 for (auto& feeder : effects_feeders_) |
| 356 feeder->Start(); | 353 feeder->Start(1.0f); |
| 357 CHECK(audio_feeder_); | 354 CHECK(audio_feeder_); |
| 358 audio_feeder_->Start(); | 355 audio_feeder_->Start(playback_rate); |
| 356 base::RunLoop().Run(); | |
| 359 } | 357 } |
| 360 | 358 |
| 361 void MultizoneBackendTest::OnEndOfStream() { | 359 void MultizoneBackendTest::OnEndOfStream() { |
| 362 audio_feeder_->Stop(); | 360 audio_feeder_->Stop(); |
| 363 for (auto& feeder : effects_feeders_) | 361 for (auto& feeder : effects_feeders_) |
| 364 feeder->Stop(); | 362 feeder->Stop(); |
| 365 | 363 |
| 366 base::MessageLoop::current()->QuitWhenIdle(); | 364 base::MessageLoop::current()->QuitWhenIdle(); |
| 367 | 365 |
| 368 EXPECT_LT(audio_feeder_->max_rendering_delay_error_us(), | 366 EXPECT_LT(audio_feeder_->GetMaxRenderingDelayErrorUs(), |
| 369 kMaxRenderingDelayErrorUs) | 367 kMaxRenderingDelayErrorUs); |
| 370 << "Max positive rendering delay error: " | |
| 371 << audio_feeder_->max_positive_rendering_delay_error_us() | |
| 372 << "\nMax negative rendering delay error: " | |
| 373 << audio_feeder_->max_negative_rendering_delay_error_us() | |
| 374 << "\nAverage rendering delay error: " | |
| 375 << audio_feeder_->average_rendering_delay_error_us(); | |
| 376 } | 368 } |
| 377 | 369 |
| 378 TEST_P(MultizoneBackendTest, RenderingDelay) { | 370 TEST_P(MultizoneBackendTest, RenderingDelay) { |
| 379 std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); | |
| 380 const TestParams& params = GetParam(); | 371 const TestParams& params = GetParam(); |
| 381 int sample_rate = testing::get<0>(params); | 372 int sample_rate = testing::get<0>(params); |
| 382 float playback_rate = testing::get<1>(params); | 373 float playback_rate = testing::get<1>(params); |
| 383 | 374 |
| 384 Initialize(sample_rate, playback_rate); | 375 Initialize(sample_rate, 1 /* playback_rate_change_count */); |
|
kmackay
2017/05/27 04:13:56
Note that now, we are only testing a sample rate t
jameswest
2017/05/30 21:25:52
This preserves the previous behavior where it chan
| |
| 385 AddEffectsStreams(); | 376 AddEffectsStreams(); |
| 386 Start(); | 377 Start(playback_rate); |
| 387 base::RunLoop().Run(); | 378 } |
| 379 | |
| 380 TEST_F(MultizoneBackendTest, RenderingDelayWithMultipleRateChanges) { | |
| 381 Initialize(48000 /* sample_rate */, 10 /* playback_rate_change_count */); | |
| 382 AddEffectsStreams(); | |
| 383 Start(1.0f /* playback_rate */); | |
| 388 } | 384 } |
| 389 | 385 |
| 390 INSTANTIATE_TEST_CASE_P( | 386 INSTANTIATE_TEST_CASE_P( |
| 391 Required, | 387 Required, |
| 392 MultizoneBackendTest, | 388 MultizoneBackendTest, |
| 393 testing::Combine(::testing::Values(8000, | 389 testing::Combine(::testing::Values(8000, |
| 394 11025, | 390 11025, |
| 395 12000, | 391 12000, |
| 396 16000, | 392 16000, |
| 397 22050, | 393 22050, |
| 398 24000, | 394 24000, |
| 399 32000, | 395 32000, |
| 400 44100, | 396 44100, |
| 401 48000), | 397 48000), |
| 402 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f))); | 398 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f))); |
| 403 | 399 |
| 404 INSTANTIATE_TEST_CASE_P( | 400 INSTANTIATE_TEST_CASE_P( |
| 405 Optional, | 401 Optional, |
| 406 MultizoneBackendTest, | 402 MultizoneBackendTest, |
| 407 testing::Combine(::testing::Values(64000, 88200, 96000), | 403 testing::Combine(::testing::Values(64000, 88200, 96000), |
| 408 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f))); | 404 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f))); |
| 409 | 405 |
| 410 } // namespace media | 406 } // namespace media |
| 411 } // namespace chromecast | 407 } // namespace chromecast |
| OLD | NEW |