Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 | 141 |
| 142 void AudioRendererImpl::SetMediaTime(base::TimeDelta time) { | 142 void AudioRendererImpl::SetMediaTime(base::TimeDelta time) { |
| 143 DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")"; | 143 DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")"; |
| 144 DCHECK(task_runner_->BelongsToCurrentThread()); | 144 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 145 | 145 |
| 146 base::AutoLock auto_lock(lock_); | 146 base::AutoLock auto_lock(lock_); |
| 147 DCHECK(!rendering_); | 147 DCHECK(!rendering_); |
| 148 DCHECK_EQ(state_, kFlushed); | 148 DCHECK_EQ(state_, kFlushed); |
| 149 | 149 |
| 150 start_timestamp_ = time; | 150 start_timestamp_ = time; |
| 151 ended_timestamp_ = kInfiniteDuration(); | |
| 151 audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate())); | 152 audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate())); |
| 152 } | 153 } |
| 153 | 154 |
| 154 base::TimeDelta AudioRendererImpl::CurrentMediaTime() { | 155 base::TimeDelta AudioRendererImpl::CurrentMediaTime() { |
| 155 DVLOG(1) << __FUNCTION__; | 156 DVLOG(1) << __FUNCTION__; |
| 156 DCHECK(task_runner_->BelongsToCurrentThread()); | 157 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 157 | 158 |
| 158 // TODO(scherkus): Finish implementing when ready to switch Pipeline to using | 159 // TODO(scherkus): Finish implementing when ready to switch Pipeline to using |
| 159 // TimeSource http://crbug.com/370634 | 160 // TimeSource http://crbug.com/370634 |
| 160 NOTIMPLEMENTED(); | 161 NOTIMPLEMENTED(); |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 } | 541 } |
| 541 | 542 |
| 542 int AudioRendererImpl::Render(AudioBus* audio_bus, | 543 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 543 int audio_delay_milliseconds) { | 544 int audio_delay_milliseconds) { |
| 544 const int requested_frames = audio_bus->frames(); | 545 const int requested_frames = audio_bus->frames(); |
| 545 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 546 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( |
| 546 audio_delay_milliseconds); | 547 audio_delay_milliseconds); |
| 547 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 548 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
| 548 audio_parameters_.sample_rate()); | 549 audio_parameters_.sample_rate()); |
| 549 int frames_written = 0; | 550 int frames_written = 0; |
| 550 base::Closure time_cb; | |
| 551 { | 551 { |
| 552 base::AutoLock auto_lock(lock_); | 552 base::AutoLock auto_lock(lock_); |
| 553 | 553 |
| 554 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 554 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
| 555 if (!algorithm_) { | 555 if (!algorithm_) { |
| 556 audio_clock_->WroteAudio( | 556 audio_clock_->WroteAudio( |
| 557 0, requested_frames, delay_frames, playback_rate_); | 557 0, requested_frames, delay_frames, playback_rate_); |
| 558 return 0; | 558 return 0; |
| 559 } | 559 } |
| 560 | 560 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 580 // We use the following conditions to determine underflow: | 580 // We use the following conditions to determine underflow: |
| 581 // 1) Algorithm can not fill the audio callback buffer | 581 // 1) Algorithm can not fill the audio callback buffer |
| 582 // 2) We have NOT received an end of stream buffer | 582 // 2) We have NOT received an end of stream buffer |
| 583 // 3) We are in the kPlaying state | 583 // 3) We are in the kPlaying state |
| 584 // | 584 // |
| 585 // Otherwise the buffer has data we can send to the device. | 585 // Otherwise the buffer has data we can send to the device. |
| 586 if (algorithm_->frames_buffered() > 0) { | 586 if (algorithm_->frames_buffered() > 0) { |
| 587 frames_written = | 587 frames_written = |
| 588 algorithm_->FillBuffer(audio_bus, requested_frames, playback_rate_); | 588 algorithm_->FillBuffer(audio_bus, requested_frames, playback_rate_); |
| 589 } | 589 } |
| 590 audio_clock_->WroteAudio( | |
| 591 frames_written, requested_frames, delay_frames, playback_rate_); | |
| 592 | 590 |
| 591 int frames_after_end_of_stream = 0; | |
| 593 if (frames_written == 0) { | 592 if (frames_written == 0) { |
| 594 if (received_end_of_stream_ && !rendered_end_of_stream_ && | 593 if (received_end_of_stream_) { |
| 595 !audio_clock_->audio_data_buffered()) { | 594 if (ended_timestamp_ == kInfiniteDuration()) |
| 596 rendered_end_of_stream_ = true; | 595 ended_timestamp_ = audio_clock_->latest_media_timestamp(); |
| 597 task_runner_->PostTask(FROM_HERE, ended_cb_); | 596 frames_after_end_of_stream = requested_frames; |
| 598 } else if (!received_end_of_stream_ && state_ == kPlaying) { | 597 } else if (state_ == kPlaying && |
| 599 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | 598 buffering_state_ != BUFFERING_HAVE_NOTHING) { |
| 600 algorithm_->IncreaseQueueCapacity(); | 599 algorithm_->IncreaseQueueCapacity(); |
| 601 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 600 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
|
DaleCurtis
2014/08/29 20:17:23
Shouldn't you be accounting for the frames written
scherkus (not reviewing)
2014/08/29 20:32:02
Not sure I follow.
What case are you thinking of?
DaleCurtis
2014/08/29 20:59:17
Audio still advances from the last write cycle des
scherkus (not reviewing)
2014/08/29 21:29:00
The moment we enter underflow we don't want to adv
DaleCurtis
2014/08/29 22:04:42
Okay, this makes sense, but could do with a commen
| |
| 602 } | |
| 603 } | 601 } |
| 604 } | 602 } |
| 605 | 603 |
| 604 audio_clock_->WroteAudio(frames_written + frames_after_end_of_stream, | |
| 605 requested_frames, | |
| 606 delay_frames, | |
| 607 playback_rate_); | |
| 608 | |
| 606 if (CanRead_Locked()) { | 609 if (CanRead_Locked()) { |
| 607 task_runner_->PostTask(FROM_HERE, | 610 task_runner_->PostTask(FROM_HERE, |
| 608 base::Bind(&AudioRendererImpl::AttemptRead, | 611 base::Bind(&AudioRendererImpl::AttemptRead, |
| 609 weak_factory_.GetWeakPtr())); | 612 weak_factory_.GetWeakPtr())); |
| 610 } | 613 } |
| 611 | 614 |
| 612 // Firing |ended_cb_| means we no longer need to run |time_cb_|. | 615 if (last_timestamp_update_ != audio_clock_->current_media_timestamp()) { |
| 613 if (!rendered_end_of_stream_ && | |
| 614 last_timestamp_update_ != audio_clock_->current_media_timestamp()) { | |
| 615 // Since |max_time| uses linear interpolation, only provide an upper bound | 616 // Since |max_time| uses linear interpolation, only provide an upper bound |
| 616 // that is for audio data at the same playback rate. Failing to do so can | 617 // that is for audio data at the same playback rate. Failing to do so can |
| 617 // make time jump backwards when the linear interpolated time advances | 618 // make time jump backwards when the linear interpolated time advances |
| 618 // past buffered regions of audio at different rates. | 619 // past buffered regions of audio at different rates. |
| 619 last_timestamp_update_ = audio_clock_->current_media_timestamp(); | 620 last_timestamp_update_ = audio_clock_->current_media_timestamp(); |
| 620 base::TimeDelta max_time = | 621 base::TimeDelta max_time = |
| 621 last_timestamp_update_ + | 622 last_timestamp_update_ + |
| 622 audio_clock_->contiguous_audio_data_buffered_at_same_rate(); | 623 audio_clock_->contiguous_audio_data_buffered_at_same_rate(); |
| 623 time_cb = base::Bind(time_cb_, last_timestamp_update_, max_time); | 624 task_runner_->PostTask( |
| 625 FROM_HERE, base::Bind(time_cb_, last_timestamp_update_, max_time)); | |
| 626 | |
| 627 if (last_timestamp_update_ >= ended_timestamp_ && | |
| 628 !rendered_end_of_stream_) { | |
| 629 rendered_end_of_stream_ = true; | |
| 630 task_runner_->PostTask(FROM_HERE, ended_cb_); | |
| 631 } | |
| 624 } | 632 } |
| 625 } | 633 } |
| 626 | 634 |
| 627 if (!time_cb.is_null()) | |
| 628 task_runner_->PostTask(FROM_HERE, time_cb); | |
| 629 | |
| 630 DCHECK_LE(frames_written, requested_frames); | 635 DCHECK_LE(frames_written, requested_frames); |
| 631 return frames_written; | 636 return frames_written; |
| 632 } | 637 } |
| 633 | 638 |
| 634 void AudioRendererImpl::OnRenderError() { | 639 void AudioRendererImpl::OnRenderError() { |
| 635 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 640 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
| 636 // of trying to gracefully fall back to a fake sink. It's very likely | 641 // of trying to gracefully fall back to a fake sink. It's very likely |
| 637 // OnRenderError() should be removed and the audio stack handle errors without | 642 // OnRenderError() should be removed and the audio stack handle errors without |
| 638 // notifying clients. See http://crbug.com/234708 for details. | 643 // notifying clients. See http://crbug.com/234708 for details. |
| 639 HistogramRendererEvent(RENDER_ERROR); | 644 HistogramRendererEvent(RENDER_ERROR); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 << buffering_state; | 704 << buffering_state; |
| 700 DCHECK_NE(buffering_state_, buffering_state); | 705 DCHECK_NE(buffering_state_, buffering_state); |
| 701 lock_.AssertAcquired(); | 706 lock_.AssertAcquired(); |
| 702 buffering_state_ = buffering_state; | 707 buffering_state_ = buffering_state; |
| 703 | 708 |
| 704 task_runner_->PostTask(FROM_HERE, | 709 task_runner_->PostTask(FROM_HERE, |
| 705 base::Bind(buffering_state_cb_, buffering_state_)); | 710 base::Bind(buffering_state_cb_, buffering_state_)); |
| 706 } | 711 } |
| 707 | 712 |
| 708 } // namespace media | 713 } // namespace media |
| OLD | NEW |