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

Side by Side Diff: media/filters/audio_renderer_impl.cc

Issue 384543002: Move bulk of media::AudioRendererImpl::Render() logic to media thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "media/filters/audio_renderer_impl.h" 5 #include "media/filters/audio_renderer_impl.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 22 matching lines...) Expand all
33 RENDER_EVENT_MAX = RENDER_ERROR, 33 RENDER_EVENT_MAX = RENDER_ERROR,
34 }; 34 };
35 35
36 void HistogramRendererEvent(AudioRendererEvent event) { 36 void HistogramRendererEvent(AudioRendererEvent event) {
37 UMA_HISTOGRAM_ENUMERATION( 37 UMA_HISTOGRAM_ENUMERATION(
38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); 38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1);
39 } 39 }
40 40
41 } // namespace 41 } // namespace
42 42
43 AudioRendererImpl::RenderResult::RenderResult()
44 : requested_frames(0),
45 delay_frames(0),
46 frames_written(0),
47 playback_rate(0),
48 endpoint_timestamp(kNoTimestamp()) {
49 }
50
43 AudioRendererImpl::AudioRendererImpl( 51 AudioRendererImpl::AudioRendererImpl(
44 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 52 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
45 media::AudioRendererSink* sink, 53 media::AudioRendererSink* sink,
46 ScopedVector<AudioDecoder> decoders, 54 ScopedVector<AudioDecoder> decoders,
47 const SetDecryptorReadyCB& set_decryptor_ready_cb, 55 const SetDecryptorReadyCB& set_decryptor_ready_cb,
48 AudioHardwareConfig* hardware_config) 56 AudioHardwareConfig* hardware_config)
49 : task_runner_(task_runner), 57 : task_runner_(task_runner),
50 sink_(sink), 58 sink_(sink),
51 audio_buffer_stream_(task_runner, 59 audio_buffer_stream_(task_runner,
52 decoders.Pass(), 60 decoders.Pass(),
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 177
170 DCHECK_EQ(state_, kFlushed); 178 DCHECK_EQ(state_, kFlushed);
171 DCHECK(!flush_cb_.is_null()); 179 DCHECK(!flush_cb_.is_null());
172 180
173 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); 181 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
174 received_end_of_stream_ = false; 182 received_end_of_stream_ = false;
175 rendered_end_of_stream_ = false; 183 rendered_end_of_stream_ = false;
176 184
177 // Flush() may have been called while underflowed/not fully buffered. 185 // Flush() may have been called while underflowed/not fully buffered.
178 if (buffering_state_ != BUFFERING_HAVE_NOTHING) 186 if (buffering_state_ != BUFFERING_HAVE_NOTHING)
179 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 187 SetBufferingState(BUFFERING_HAVE_NOTHING);
180 188
181 splicer_->Reset(); 189 splicer_->Reset();
182 if (buffer_converter_) 190 if (buffer_converter_)
183 buffer_converter_->Reset(); 191 buffer_converter_->Reset();
184 algorithm_->FlushBuffers(); 192 algorithm_->FlushBuffers();
185 } 193 }
186 194
187 // Changes in buffering state are always posted. Flush callback must only be 195 // Changes in buffering state are always posted. Flush callback must only be
188 // run after buffering state has been set back to nothing. 196 // run after buffering state has been set back to nothing.
189 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); 197 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_));
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 418
411 if (!splicer_->HasNextBuffer()) { 419 if (!splicer_->HasNextBuffer()) {
412 AttemptRead_Locked(); 420 AttemptRead_Locked();
413 return; 421 return;
414 } 422 }
415 423
416 bool need_another_buffer = false; 424 bool need_another_buffer = false;
417 while (splicer_->HasNextBuffer()) 425 while (splicer_->HasNextBuffer())
418 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); 426 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer());
419 427
420 if (!need_another_buffer && !CanRead_Locked()) 428 if (!need_another_buffer)
421 return; 429 return;
422 430
423 AttemptRead_Locked(); 431 AttemptRead_Locked();
424 } 432 }
425 433
426 bool AudioRendererImpl::HandleSplicerBuffer_Locked( 434 bool AudioRendererImpl::HandleSplicerBuffer_Locked(
427 const scoped_refptr<AudioBuffer>& buffer) { 435 const scoped_refptr<AudioBuffer>& buffer) {
428 lock_.AssertAcquired(); 436 lock_.AssertAcquired();
429 if (buffer->end_of_stream()) { 437 if (buffer->end_of_stream()) {
430 received_end_of_stream_ = true; 438 received_end_of_stream_ = true;
(...skipping 25 matching lines...) Expand all
456 NOTREACHED(); 464 NOTREACHED();
457 return false; 465 return false;
458 466
459 case kFlushed: 467 case kFlushed:
460 DCHECK(!pending_read_); 468 DCHECK(!pending_read_);
461 return false; 469 return false;
462 470
463 case kPlaying: 471 case kPlaying:
464 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { 472 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) {
465 if (buffering_state_ == BUFFERING_HAVE_NOTHING) 473 if (buffering_state_ == BUFFERING_HAVE_NOTHING)
466 SetBufferingState_Locked(BUFFERING_HAVE_ENOUGH); 474 SetBufferingState(BUFFERING_HAVE_ENOUGH);
467 return false; 475 return false;
468 } 476 }
469 return true; 477 return true;
470 478
471 case kStopped: 479 case kStopped:
472 return false; 480 return false;
473 } 481 }
474 return false; 482 return false;
475 } 483 }
476 484
477 void AudioRendererImpl::AttemptRead() {
478 base::AutoLock auto_lock(lock_);
479 AttemptRead_Locked();
480 }
481
482 void AudioRendererImpl::AttemptRead_Locked() { 485 void AudioRendererImpl::AttemptRead_Locked() {
483 DCHECK(task_runner_->BelongsToCurrentThread()); 486 DCHECK(task_runner_->BelongsToCurrentThread());
484 lock_.AssertAcquired(); 487 lock_.AssertAcquired();
485 488
486 if (!CanRead_Locked())
487 return;
488
489 pending_read_ = true;
490 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady,
491 weak_factory_.GetWeakPtr()));
492 }
493
494 bool AudioRendererImpl::CanRead_Locked() {
495 lock_.AssertAcquired();
496
497 switch (state_) { 489 switch (state_) {
498 case kUninitialized: 490 case kUninitialized:
499 case kInitializing: 491 case kInitializing:
500 case kFlushing: 492 case kFlushing:
501 case kFlushed: 493 case kFlushed:
502 case kStopped: 494 case kStopped:
503 return false; 495 return;
504 496
505 case kPlaying: 497 case kPlaying:
506 break; 498 break;
507 } 499 }
508 500
509 return !pending_read_ && !received_end_of_stream_ && 501 if (pending_read_ || received_end_of_stream_ || algorithm_->IsQueueFull())
510 !algorithm_->IsQueueFull(); 502 return;
503
504 pending_read_ = true;
505 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady,
506 weak_factory_.GetWeakPtr()));
511 } 507 }
512 508
513 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { 509 void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
514 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; 510 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
515 DCHECK(task_runner_->BelongsToCurrentThread()); 511 DCHECK(task_runner_->BelongsToCurrentThread());
516 DCHECK_GE(playback_rate, 0); 512 DCHECK_GE(playback_rate, 0);
517 DCHECK(sink_); 513 DCHECK(sink_);
518 514
519 base::AutoLock auto_lock(lock_); 515 base::AutoLock auto_lock(lock_);
520 516
(...skipping 19 matching lines...) Expand all
540 536
541 bool AudioRendererImpl::IsBeforeStartTime( 537 bool AudioRendererImpl::IsBeforeStartTime(
542 const scoped_refptr<AudioBuffer>& buffer) { 538 const scoped_refptr<AudioBuffer>& buffer) {
543 DCHECK_EQ(state_, kPlaying); 539 DCHECK_EQ(state_, kPlaying);
544 return buffer && !buffer->end_of_stream() && 540 return buffer && !buffer->end_of_stream() &&
545 (buffer->timestamp() + buffer->duration()) < start_timestamp_; 541 (buffer->timestamp() + buffer->duration()) < start_timestamp_;
546 } 542 }
547 543
548 int AudioRendererImpl::Render(AudioBus* audio_bus, 544 int AudioRendererImpl::Render(AudioBus* audio_bus,
549 int audio_delay_milliseconds) { 545 int audio_delay_milliseconds) {
550 const int requested_frames = audio_bus->frames(); 546 DVLOG(2) << __FUNCTION__;
DaleCurtis 2014/07/10 23:37:00 Probably you should remove this, or make DVLOG(3).
551 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( 547 base::TimeDelta playback_delay =
552 audio_delay_milliseconds); 548 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
553 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * 549
554 audio_parameters_.sample_rate()); 550 RenderResult result;
555 int frames_written = 0; 551 result.requested_frames = audio_bus->frames();
556 base::Closure time_cb; 552 result.delay_frames = static_cast<int>(playback_delay.InSecondsF() *
553 audio_parameters_.sample_rate());
554
557 { 555 {
558 base::AutoLock auto_lock(lock_); 556 base::AutoLock auto_lock(lock_);
559 557 if (state_ == kPlaying && algorithm_->frames_buffered() > 0) {
560 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. 558 result.frames_written =
561 if (!algorithm_) { 559 algorithm_->FillBuffer(audio_bus, result.requested_frames);
562 audio_clock_->WroteSilence(requested_frames, delay_frames); 560 result.playback_rate = algorithm_->playback_rate();
563 return 0; 561 result.endpoint_timestamp = algorithm_->GetTime();
564 }
565
566 float playback_rate = algorithm_->playback_rate();
567 if (playback_rate == 0) {
568 audio_clock_->WroteSilence(requested_frames, delay_frames);
569 return 0;
570 }
571
572 // Mute audio by returning 0 when not playing.
573 if (state_ != kPlaying) {
574 audio_clock_->WroteSilence(requested_frames, delay_frames);
575 return 0;
576 }
577
578 // We use the following conditions to determine end of playback:
579 // 1) Algorithm can not fill the audio callback buffer
580 // 2) We received an end of stream buffer
581 // 3) We haven't already signalled that we've ended
582 // 4) We've played all known audio data sent to hardware
583 //
584 // We use the following conditions to determine underflow:
585 // 1) Algorithm can not fill the audio callback buffer
586 // 2) We have NOT received an end of stream buffer
587 // 3) We are in the kPlaying state
588 //
589 // Otherwise the buffer has data we can send to the device.
590 const base::TimeDelta media_timestamp_before_filling =
591 audio_clock_->CurrentMediaTimestamp();
592 if (algorithm_->frames_buffered() > 0) {
593 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
594 audio_clock_->WroteAudio(
595 frames_written, delay_frames, playback_rate, algorithm_->GetTime());
596 }
597 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
598
599 if (frames_written == 0) {
600 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
601 audio_clock_->CurrentMediaTimestamp() ==
602 audio_clock_->last_endpoint_timestamp()) {
603 rendered_end_of_stream_ = true;
604 ended_cb_.Run();
605 } else if (!received_end_of_stream_ && state_ == kPlaying) {
606 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
607 algorithm_->IncreaseQueueCapacity();
608 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
609 }
610 }
611 }
612
613 if (CanRead_Locked()) {
614 task_runner_->PostTask(FROM_HERE,
615 base::Bind(&AudioRendererImpl::AttemptRead,
616 weak_factory_.GetWeakPtr()));
617 }
618
619 // We only want to execute |time_cb_| if time has progressed and we haven't
620 // signaled end of stream yet.
621 if (media_timestamp_before_filling !=
622 audio_clock_->CurrentMediaTimestamp() &&
623 !rendered_end_of_stream_) {
624 time_cb = base::Bind(time_cb_,
625 audio_clock_->CurrentMediaTimestamp(),
626 audio_clock_->last_endpoint_timestamp());
627 } 562 }
628 } 563 }
629 564
630 if (!time_cb.is_null()) 565 task_runner_->PostTask(
631 task_runner_->PostTask(FROM_HERE, time_cb); 566 FROM_HERE,
567 base::Bind(
568 &AudioRendererImpl::DidRender, weak_factory_.GetWeakPtr(), result));
632 569
633 DCHECK_LE(frames_written, requested_frames); 570 return result.frames_written;
634 return frames_written; 571 }
572
573 void AudioRendererImpl::DidRender(RenderResult result) {
574 DCHECK(task_runner_->BelongsToCurrentThread());
575 DVLOG(2) << __FUNCTION__;
DaleCurtis 2014/07/10 23:37:00 Ditto.
576
577 base::AutoLock auto_lock(lock_);
DaleCurtis 2014/07/10 23:37:00 Only needed when accessing algorithm_ and reading?
578 if (state_ == kStopped)
579 return;
580
581 base::TimeDelta previous_media_timestamp =
582 audio_clock_->CurrentMediaTimestamp();
583
584 if (result.frames_written > 0) {
585 audio_clock_->WroteAudio(result.frames_written,
586 result.delay_frames,
587 result.playback_rate,
588 result.endpoint_timestamp);
589 }
590 audio_clock_->WroteSilence(result.requested_frames - result.frames_written,
591 result.delay_frames);
592
593 // We use the following conditions to determine end of playback:
594 // 1) Algorithm can not fill the audio callback buffer
595 // 2) We received an end of stream buffer
596 // 3) We haven't already signalled that we've ended
597 // 4) We've played all known audio data sent to hardware
598 //
599 // We use the following conditions to determine underflow:
600 // 1) Algorithm can not fill the audio callback buffer
601 // 2) We have NOT received an end of stream buffer
602 // 3) We are in the kPlaying state
603 if (result.frames_written == 0) {
604 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
605 audio_clock_->CurrentMediaTimestamp() ==
606 audio_clock_->last_endpoint_timestamp()) {
607 rendered_end_of_stream_ = true;
608 ended_cb_.Run();
609 } else if (!received_end_of_stream_ && state_ == kPlaying) {
610 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
611 algorithm_->IncreaseQueueCapacity();
612 SetBufferingState(BUFFERING_HAVE_NOTHING);
613 }
614 }
615 }
616
617 // Don't fire time updates if we don't need to (e.g., time hasn't changed,
618 // playback has ended).
619 if (previous_media_timestamp != audio_clock_->CurrentMediaTimestamp() &&
620 !rendered_end_of_stream_) {
621 time_cb_.Run(audio_clock_->CurrentMediaTimestamp(),
622 audio_clock_->last_endpoint_timestamp());
623 }
624
625 AttemptRead_Locked();
635 } 626 }
636 627
637 void AudioRendererImpl::OnRenderError() { 628 void AudioRendererImpl::OnRenderError() {
638 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead 629 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead
639 // of trying to gracefully fall back to a fake sink. It's very likely 630 // of trying to gracefully fall back to a fake sink. It's very likely
640 // OnRenderError() should be removed and the audio stack handle errors without 631 // OnRenderError() should be removed and the audio stack handle errors without
641 // notifying clients. See http://crbug.com/234708 for details. 632 // notifying clients. See http://crbug.com/234708 for details.
642 HistogramRendererEvent(RENDER_ERROR); 633 HistogramRendererEvent(RENDER_ERROR);
643 error_cb_.Run(PIPELINE_ERROR_DECODE); 634 error_cb_.Run(PIPELINE_ERROR_DECODE);
644 } 635 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 DCHECK(task_runner_->BelongsToCurrentThread()); 678 DCHECK(task_runner_->BelongsToCurrentThread());
688 DCHECK(expecting_config_changes_); 679 DCHECK(expecting_config_changes_);
689 buffer_converter_->ResetTimestampState(); 680 buffer_converter_->ResetTimestampState();
690 // Drain flushed buffers from the converter so the AudioSplicer receives all 681 // Drain flushed buffers from the converter so the AudioSplicer receives all
691 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should 682 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should
692 // only appear after config changes, AddInput() should never fail here. 683 // only appear after config changes, AddInput() should never fail here.
693 while (buffer_converter_->HasNextBuffer()) 684 while (buffer_converter_->HasNextBuffer())
694 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); 685 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer()));
695 } 686 }
696 687
697 void AudioRendererImpl::SetBufferingState_Locked( 688 void AudioRendererImpl::SetBufferingState(BufferingState buffering_state) {
698 BufferingState buffering_state) {
699 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " 689 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> "
700 << buffering_state; 690 << buffering_state;
691 DCHECK(task_runner_->BelongsToCurrentThread());
701 DCHECK_NE(buffering_state_, buffering_state); 692 DCHECK_NE(buffering_state_, buffering_state);
702 lock_.AssertAcquired();
703 buffering_state_ = buffering_state; 693 buffering_state_ = buffering_state;
704 694
705 task_runner_->PostTask(FROM_HERE, 695 task_runner_->PostTask(FROM_HERE,
706 base::Bind(buffering_state_cb_, buffering_state_)); 696 base::Bind(buffering_state_cb_, buffering_state_));
707 } 697 }
708 698
709 } // namespace media 699 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698