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

Side by Side Diff: chromecast/media/cma/backend/multizone_backend_unittest.cc

Issue 2557513002: [Chromecast] Add support for different playback rates to ALSA backend (Closed)
Patch Set: use CreateEmptyBuffer Created 4 years 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 unified diff | Download patch
OLDNEW
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>
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 48
49 void IgnoreEos() {} 49 void IgnoreEos() {}
50 50
51 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate { 51 class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
52 public: 52 public:
53 BufferFeeder(const AudioConfig& config, 53 BufferFeeder(const AudioConfig& config,
54 bool effects_only, 54 bool effects_only,
55 const base::Closure& eos_cb); 55 const base::Closure& eos_cb);
56 ~BufferFeeder() override {} 56 ~BufferFeeder() override {}
57 57
58 void Initialize(); 58 void Initialize(float playback_rate);
59 void Start(); 59 void Start();
60 void Stop(); 60 void Stop();
61 61
62 int64_t max_rendering_delay_error_us() { 62 int64_t max_rendering_delay_error_us() {
63 return max_rendering_delay_error_us_; 63 return max_rendering_delay_error_us_;
64 } 64 }
65 65
66 int64_t max_positive_rendering_delay_error_us() { 66 int64_t max_positive_rendering_delay_error_us() {
67 return max_positive_rendering_delay_error_us_; 67 return max_positive_rendering_delay_error_us_;
68 } 68 }
(...skipping 26 matching lines...) Expand all
95 DCHECK(thread_checker_.CalledOnValidThread()); 95 DCHECK(thread_checker_.CalledOnValidThread());
96 ASSERT_TRUE(false); 96 ASSERT_TRUE(false);
97 } 97 }
98 void OnVideoResolutionChanged(const Size& size) override { 98 void OnVideoResolutionChanged(const Size& size) override {
99 DCHECK(thread_checker_.CalledOnValidThread()); 99 DCHECK(thread_checker_.CalledOnValidThread());
100 } 100 }
101 101
102 const AudioConfig config_; 102 const AudioConfig config_;
103 const bool effects_only_; 103 const bool effects_only_;
104 const base::Closure eos_cb_; 104 const base::Closure eos_cb_;
105 double original_playback_rate_;
106 double playback_rate_;
105 int64_t max_rendering_delay_error_us_; 107 int64_t max_rendering_delay_error_us_;
106 int64_t max_positive_rendering_delay_error_us_; 108 int64_t max_positive_rendering_delay_error_us_;
107 int64_t max_negative_rendering_delay_error_us_; 109 int64_t max_negative_rendering_delay_error_us_;
108 int64_t total_rendering_delay_error_us_; 110 int64_t total_rendering_delay_error_us_;
109 size_t sample_count_; 111 size_t sample_count_;
110 bool feeding_completed_; 112 bool feeding_completed_;
111 std::unique_ptr<TaskRunnerImpl> task_runner_; 113 std::unique_ptr<TaskRunnerImpl> task_runner_;
112 std::unique_ptr<MediaPipelineBackend> backend_; 114 std::unique_ptr<MediaPipelineBackend> backend_;
113 MediaPipelineBackend::AudioDecoder* decoder_; 115 MediaPipelineBackend::AudioDecoder* decoder_;
114 int64_t push_limit_us_; 116 int64_t push_limit_us_;
115 int64_t last_push_length_us_; 117 int64_t last_push_length_us_;
116 int64_t pushed_us_; 118 int64_t pushed_us_;
117 int64_t next_push_playback_timestamp_; 119 int64_t next_push_playback_timestamp_;
118 scoped_refptr<DecoderBufferBase> pending_buffer_; 120 scoped_refptr<DecoderBufferBase> pending_buffer_;
119 base::ThreadChecker thread_checker_; 121 base::ThreadChecker thread_checker_;
120 122
121 DISALLOW_COPY_AND_ASSIGN(BufferFeeder); 123 DISALLOW_COPY_AND_ASSIGN(BufferFeeder);
122 }; 124 };
123 125
124 } // namespace 126 } // namespace
125 127
126 class MultizoneBackendTest : public testing::TestWithParam<int> { 128 using TestParams = std::tr1::tuple<int, // sample rate
129 float>; // playback rate
130
131 class MultizoneBackendTest : public testing::TestWithParam<TestParams> {
127 public: 132 public:
128 MultizoneBackendTest(); 133 MultizoneBackendTest();
129 ~MultizoneBackendTest() override; 134 ~MultizoneBackendTest() override;
130 135
131 void SetUp() override { 136 void SetUp() override {
132 srand(12345); 137 srand(12345);
133 CastMediaShlib::Initialize(base::CommandLine::ForCurrentProcess()->argv()); 138 CastMediaShlib::Initialize(base::CommandLine::ForCurrentProcess()->argv());
134 } 139 }
135 140
136 void TearDown() override { 141 void TearDown() override {
137 // Pipeline must be destroyed before finalizing media shlib. 142 // Pipeline must be destroyed before finalizing media shlib.
138 audio_feeder_.reset(); 143 audio_feeder_.reset();
139 effects_feeders_.clear(); 144 effects_feeders_.clear();
140 CastMediaShlib::Finalize(); 145 CastMediaShlib::Finalize();
141 } 146 }
142 147
143 void AddEffectsStreams(); 148 void AddEffectsStreams();
144 149
145 void Initialize(int sample_rate); 150 void Initialize(int sample_rate, float playback_rate);
146 void Start(); 151 void Start();
147 void OnEndOfStream(); 152 void OnEndOfStream();
148 153
149 private: 154 private:
150 std::vector<std::unique_ptr<BufferFeeder>> effects_feeders_; 155 std::vector<std::unique_ptr<BufferFeeder>> effects_feeders_;
151 std::unique_ptr<BufferFeeder> audio_feeder_; 156 std::unique_ptr<BufferFeeder> audio_feeder_;
152 157
153 DISALLOW_COPY_AND_ASSIGN(MultizoneBackendTest); 158 DISALLOW_COPY_AND_ASSIGN(MultizoneBackendTest);
154 }; 159 };
155 160
156 namespace { 161 namespace {
157 162
158 BufferFeeder::BufferFeeder(const AudioConfig& config, 163 BufferFeeder::BufferFeeder(const AudioConfig& config,
159 bool effects_only, 164 bool effects_only,
160 const base::Closure& eos_cb) 165 const base::Closure& eos_cb)
161 : config_(config), 166 : config_(config),
162 effects_only_(effects_only), 167 effects_only_(effects_only),
163 eos_cb_(eos_cb), 168 eos_cb_(eos_cb),
169 original_playback_rate_(1.0),
170 playback_rate_(1.0),
164 max_rendering_delay_error_us_(0), 171 max_rendering_delay_error_us_(0),
165 max_positive_rendering_delay_error_us_(0), 172 max_positive_rendering_delay_error_us_(0),
166 max_negative_rendering_delay_error_us_(0), 173 max_negative_rendering_delay_error_us_(0),
167 total_rendering_delay_error_us_(0), 174 total_rendering_delay_error_us_(0),
168 sample_count_(0), 175 sample_count_(0),
169 feeding_completed_(false), 176 feeding_completed_(false),
170 task_runner_(new TaskRunnerImpl()), 177 task_runner_(new TaskRunnerImpl()),
171 decoder_(nullptr), 178 decoder_(nullptr),
172 push_limit_us_(effects_only_ ? 0 : kPushTimeUs), 179 push_limit_us_(effects_only_ ? 0 : kPushTimeUs),
173 last_push_length_us_(0), 180 last_push_length_us_(0),
174 pushed_us_(0), 181 pushed_us_(0),
175 next_push_playback_timestamp_(kNoTimestamp) { 182 next_push_playback_timestamp_(kNoTimestamp) {
176 CHECK(!eos_cb_.is_null()); 183 CHECK(!eos_cb_.is_null());
177 } 184 }
178 185
179 void BufferFeeder::Initialize() { 186 void BufferFeeder::Initialize(float playback_rate) {
187 original_playback_rate_ = playback_rate_ = playback_rate;
180 MediaPipelineDeviceParams params( 188 MediaPipelineDeviceParams params(
181 MediaPipelineDeviceParams::kModeIgnorePts, 189 MediaPipelineDeviceParams::kModeIgnorePts,
182 effects_only_ ? MediaPipelineDeviceParams::kAudioStreamSoundEffects 190 effects_only_ ? MediaPipelineDeviceParams::kAudioStreamSoundEffects
183 : MediaPipelineDeviceParams::kAudioStreamNormal, 191 : MediaPipelineDeviceParams::kAudioStreamNormal,
184 task_runner_.get()); 192 task_runner_.get());
185 backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params)); 193 backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params));
186 CHECK(backend_); 194 CHECK(backend_);
187 195
188 decoder_ = backend_->CreateAudioDecoder(); 196 decoder_ = backend_->CreateAudioDecoder();
189 CHECK(decoder_); 197 CHECK(decoder_);
190 ASSERT_TRUE(decoder_->SetConfig(config_)); 198 ASSERT_TRUE(decoder_->SetConfig(config_));
191 decoder_->SetDelegate(this); 199 decoder_->SetDelegate(this);
192 200
193 ASSERT_TRUE(backend_->Initialize()); 201 ASSERT_TRUE(backend_->Initialize());
202 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate));
194 } 203 }
195 204
196 void BufferFeeder::Start() { 205 void BufferFeeder::Start() {
197 ASSERT_TRUE(backend_->Start(kStartPts)); 206 ASSERT_TRUE(backend_->Start(kStartPts));
198 base::ThreadTaskRunnerHandle::Get()->PostTask( 207 base::ThreadTaskRunnerHandle::Get()->PostTask(
199 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); 208 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
200 } 209 }
201 210
202 void BufferFeeder::Stop() { 211 void BufferFeeder::Stop() {
203 feeding_completed_ = true; 212 feeding_completed_ = true;
204 ASSERT_TRUE(backend_->Stop()); 213 backend_->Stop();
205 } 214 }
206 215
207 void BufferFeeder::FeedBuffer() { 216 void BufferFeeder::FeedBuffer() {
208 CHECK(decoder_); 217 CHECK(decoder_);
209 if (feeding_completed_) 218 if (feeding_completed_)
210 return; 219 return;
211 220
221 if (!effects_only_ && pushed_us_ >= push_limit_us_ / 2 &&
222 playback_rate_ == original_playback_rate_) {
223 if (original_playback_rate_ < 1.0) {
224 playback_rate_ = original_playback_rate_ * 2;
225 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_));
226 } else {
227 playback_rate_ = original_playback_rate_ / 2;
228 ASSERT_TRUE(backend_->SetPlaybackRate(playback_rate_));
229 }
230 }
231
212 if (!effects_only_ && pushed_us_ >= push_limit_us_) { 232 if (!effects_only_ && pushed_us_ >= push_limit_us_) {
213 pending_buffer_ = new media::DecoderBufferAdapter( 233 pending_buffer_ = new media::DecoderBufferAdapter(
214 ::media::DecoderBuffer::CreateEOSBuffer()); 234 ::media::DecoderBuffer::CreateEOSBuffer());
215 feeding_completed_ = true; 235 feeding_completed_ = true;
216 last_push_length_us_ = 0; 236 last_push_length_us_ = 0;
217 } else { 237 } else {
218 int size_bytes = (rand() % 128 + 16) * 16; 238 int size_bytes = (rand() % 96 + 32) * 16;
219 int num_samples = 239 int num_samples =
220 size_bytes / (config_.bytes_per_channel * config_.channel_number); 240 size_bytes / (config_.bytes_per_channel * config_.channel_number);
221 last_push_length_us_ = 241 last_push_length_us_ = num_samples * kMicrosecondsPerSecond /
222 num_samples * kMicrosecondsPerSecond / config_.samples_per_second; 242 (config_.samples_per_second * playback_rate_);
223 scoped_refptr<::media::DecoderBuffer> silence_buffer( 243 scoped_refptr<::media::DecoderBuffer> silence_buffer(
224 new ::media::DecoderBuffer(size_bytes)); 244 new ::media::DecoderBuffer(size_bytes));
225 memset(silence_buffer->writable_data(), 0, silence_buffer->data_size()); 245 memset(silence_buffer->writable_data(), 0, silence_buffer->data_size());
226 pending_buffer_ = new media::DecoderBufferAdapter(silence_buffer); 246 pending_buffer_ = new media::DecoderBufferAdapter(silence_buffer);
227 pending_buffer_->set_timestamp( 247 pending_buffer_->set_timestamp(
228 base::TimeDelta::FromMicroseconds(pushed_us_)); 248 base::TimeDelta::FromMicroseconds(pushed_us_));
229 } 249 }
230 BufferStatus status = decoder_->PushBuffer(pending_buffer_.get()); 250 BufferStatus status = decoder_->PushBuffer(pending_buffer_.get());
231 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed); 251 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed);
232 if (status == MediaPipelineBackend::kBufferPending) 252 if (status == MediaPipelineBackend::kBufferPending)
233 return; 253 return;
234 OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess); 254 OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess);
235 } 255 }
236 256
237 void BufferFeeder::OnEndOfStream() { 257 void BufferFeeder::OnEndOfStream() {
238 DCHECK(thread_checker_.CalledOnValidThread()); 258 DCHECK(thread_checker_.CalledOnValidThread());
239 eos_cb_.Run(); 259 eos_cb_.Run();
240 } 260 }
241 261
242 void BufferFeeder::OnPushBufferComplete(BufferStatus status) { 262 void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
243 DCHECK(thread_checker_.CalledOnValidThread()); 263 DCHECK(thread_checker_.CalledOnValidThread());
244 pending_buffer_ = nullptr; 264 pending_buffer_ = nullptr;
245 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed);
246 265
247 if (!effects_only_) { 266 if (!effects_only_) {
267 ASSERT_NE(status, MediaPipelineBackend::kBufferFailed);
248 MediaPipelineBackend::AudioDecoder::RenderingDelay delay = 268 MediaPipelineBackend::AudioDecoder::RenderingDelay delay =
249 decoder_->GetRenderingDelay(); 269 decoder_->GetRenderingDelay();
250 270
251 if (delay.timestamp_microseconds != kNoTimestamp) { 271 if (delay.timestamp_microseconds != kNoTimestamp) {
252 if (next_push_playback_timestamp_ == kNoTimestamp) { 272 if (next_push_playback_timestamp_ == kNoTimestamp) {
253 next_push_playback_timestamp_ = 273 next_push_playback_timestamp_ =
254 delay.timestamp_microseconds + delay.delay_microseconds; 274 delay.timestamp_microseconds + delay.delay_microseconds;
255 } else { 275 } else {
256 int64_t expected_next_push_playback_timestamp = 276 int64_t expected_next_push_playback_timestamp =
257 next_push_playback_timestamp_ + last_push_length_us_; 277 next_push_playback_timestamp_ + last_push_length_us_;
258 next_push_playback_timestamp_ = 278 next_push_playback_timestamp_ =
259 delay.timestamp_microseconds + delay.delay_microseconds; 279 delay.timestamp_microseconds + delay.delay_microseconds;
260 int64_t error = next_push_playback_timestamp_ - 280 int64_t error = next_push_playback_timestamp_ -
261 expected_next_push_playback_timestamp; 281 expected_next_push_playback_timestamp;
282
262 max_rendering_delay_error_us_ = 283 max_rendering_delay_error_us_ =
263 std::max(max_rendering_delay_error_us_, std::abs(error)); 284 std::max(max_rendering_delay_error_us_, std::abs(error));
264 total_rendering_delay_error_us_ += std::abs(error); 285 total_rendering_delay_error_us_ += std::abs(error);
265 if (error >= 0) { 286 if (error >= 0) {
266 max_positive_rendering_delay_error_us_ = 287 max_positive_rendering_delay_error_us_ =
267 std::max(max_positive_rendering_delay_error_us_, error); 288 std::max(max_positive_rendering_delay_error_us_, error);
268 } else { 289 } else {
269 max_negative_rendering_delay_error_us_ = 290 max_negative_rendering_delay_error_us_ =
270 std::min(max_negative_rendering_delay_error_us_, error); 291 std::min(max_negative_rendering_delay_error_us_, error);
271 } 292 }
272 sample_count_++; 293 sample_count_++;
273 } 294 }
274 } 295 }
275 } 296 }
276 pushed_us_ += last_push_length_us_; 297 pushed_us_ += last_push_length_us_;
277 298
278 if (feeding_completed_) 299 if (feeding_completed_)
279 return; 300 return;
280 301
281 base::ThreadTaskRunnerHandle::Get()->PostTask( 302 base::ThreadTaskRunnerHandle::Get()->PostTask(
282 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this))); 303 FROM_HERE, base::Bind(&BufferFeeder::FeedBuffer, base::Unretained(this)));
283 } 304 }
284 305
285 } // namespace 306 } // namespace
286 307
287 MultizoneBackendTest::MultizoneBackendTest() {} 308 MultizoneBackendTest::MultizoneBackendTest() {}
288 309
289 MultizoneBackendTest::~MultizoneBackendTest() {} 310 MultizoneBackendTest::~MultizoneBackendTest() {}
290 311
291 void MultizoneBackendTest::Initialize(int sample_rate) { 312 void MultizoneBackendTest::Initialize(int sample_rate, float playback_rate) {
292 AudioConfig config; 313 AudioConfig config;
293 config.codec = kCodecPCM; 314 config.codec = kCodecPCM;
294 config.sample_format = kSampleFormatS32; 315 config.sample_format = kSampleFormatS32;
295 config.channel_number = 2; 316 config.channel_number = 2;
296 config.bytes_per_channel = 4; 317 config.bytes_per_channel = 4;
297 config.samples_per_second = sample_rate; 318 config.samples_per_second = sample_rate;
298 319
299 audio_feeder_.reset( 320 audio_feeder_.reset(
300 new BufferFeeder(config, false /* effects_only */, 321 new BufferFeeder(config, false /* effects_only */,
301 base::Bind(&MultizoneBackendTest::OnEndOfStream, 322 base::Bind(&MultizoneBackendTest::OnEndOfStream,
302 base::Unretained(this)))); 323 base::Unretained(this))));
303 audio_feeder_->Initialize(); 324 audio_feeder_->Initialize(playback_rate);
304 } 325 }
305 326
306 void MultizoneBackendTest::AddEffectsStreams() { 327 void MultizoneBackendTest::AddEffectsStreams() {
307 AudioConfig effects_config; 328 AudioConfig effects_config;
308 effects_config.codec = kCodecPCM; 329 effects_config.codec = kCodecPCM;
309 effects_config.sample_format = kSampleFormatS16; 330 effects_config.sample_format = kSampleFormatS16;
310 effects_config.channel_number = 2; 331 effects_config.channel_number = 2;
311 effects_config.bytes_per_channel = 2; 332 effects_config.bytes_per_channel = 2;
312 effects_config.samples_per_second = 48000; 333 effects_config.samples_per_second = 48000;
313 334
314 for (int i = 0; i < kNumEffectsStreams; ++i) { 335 for (int i = 0; i < kNumEffectsStreams; ++i) {
315 std::unique_ptr<BufferFeeder> feeder(new BufferFeeder( 336 std::unique_ptr<BufferFeeder> feeder(new BufferFeeder(
316 effects_config, true /* effects_only */, base::Bind(&IgnoreEos))); 337 effects_config, true /* effects_only */, base::Bind(&IgnoreEos)));
317 feeder->Initialize(); 338 feeder->Initialize(1.0f);
318 effects_feeders_.push_back(std::move(feeder)); 339 effects_feeders_.push_back(std::move(feeder));
319 } 340 }
320 } 341 }
321 342
322 void MultizoneBackendTest::Start() { 343 void MultizoneBackendTest::Start() {
323 for (auto& feeder : effects_feeders_) 344 for (auto& feeder : effects_feeders_)
324 feeder->Start(); 345 feeder->Start();
325 CHECK(audio_feeder_); 346 CHECK(audio_feeder_);
326 audio_feeder_->Start(); 347 audio_feeder_->Start();
327 } 348 }
(...skipping 10 matching lines...) Expand all
338 << "Max positive rendering delay error: " 359 << "Max positive rendering delay error: "
339 << audio_feeder_->max_positive_rendering_delay_error_us() 360 << audio_feeder_->max_positive_rendering_delay_error_us()
340 << "\nMax negative rendering delay error: " 361 << "\nMax negative rendering delay error: "
341 << audio_feeder_->max_negative_rendering_delay_error_us() 362 << audio_feeder_->max_negative_rendering_delay_error_us()
342 << "\nAverage rendering delay error: " 363 << "\nAverage rendering delay error: "
343 << audio_feeder_->average_rendering_delay_error_us(); 364 << audio_feeder_->average_rendering_delay_error_us();
344 } 365 }
345 366
346 TEST_P(MultizoneBackendTest, RenderingDelay) { 367 TEST_P(MultizoneBackendTest, RenderingDelay) {
347 std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); 368 std::unique_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
369 const TestParams& params = GetParam();
370 int sample_rate = testing::get<0>(params);
371 float playback_rate = testing::get<1>(params);
348 372
349 Initialize(GetParam()); 373 Initialize(sample_rate, playback_rate);
350 AddEffectsStreams(); 374 AddEffectsStreams();
351 Start(); 375 Start();
352 base::RunLoop().Run(); 376 base::RunLoop().Run();
353 } 377 }
354 378
355 INSTANTIATE_TEST_CASE_P(Required, 379 INSTANTIATE_TEST_CASE_P(
356 MultizoneBackendTest, 380 Required,
357 ::testing::Values(8000, 381 MultizoneBackendTest,
358 11025, 382 testing::Combine(::testing::Values(8000,
359 12000, 383 11025,
360 16000, 384 12000,
361 22050, 385 16000,
362 24000, 386 22050,
363 32000, 387 24000,
364 44100, 388 32000,
365 48000)); 389 44100,
390 48000),
391 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f)));
366 392
367 INSTANTIATE_TEST_CASE_P(Optional, 393 INSTANTIATE_TEST_CASE_P(
368 MultizoneBackendTest, 394 Optional,
369 ::testing::Values(64000, 88200, 96000)); 395 MultizoneBackendTest,
396 testing::Combine(::testing::Values(64000, 88200, 96000),
397 ::testing::Values(0.5f, 0.99f, 1.0f, 1.01f, 2.0f)));
370 398
371 } // namespace media 399 } // namespace media
372 } // namespace chromecast 400 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698