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 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "media/base/audio_buffer.h" | 17 #include "media/base/audio_buffer.h" |
| 18 #include "media/base/audio_buffer_converter.h" | 18 #include "media/base/audio_buffer_converter.h" |
| 19 #include "media/base/audio_hardware_config.h" | 19 #include "media/base/audio_hardware_config.h" |
| 20 #include "media/base/audio_splicer.h" | 20 #include "media/base/audio_splicer.h" |
| 21 #include "media/base/bind_to_current_loop.h" | 21 #include "media/base/bind_to_current_loop.h" |
| 22 #include "media/base/demuxer_stream.h" | 22 #include "media/base/demuxer_stream.h" |
| 23 #include "media/filters/buffered_audio_tracker.h" | |
| 23 #include "media/filters/decrypting_demuxer_stream.h" | 24 #include "media/filters/decrypting_demuxer_stream.h" |
| 24 | 25 |
| 25 namespace media { | 26 namespace media { |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 enum AudioRendererEvent { | 30 enum AudioRendererEvent { |
| 30 INITIALIZED, | 31 INITIALIZED, |
| 31 RENDER_ERROR, | 32 RENDER_ERROR, |
| 32 RENDER_EVENT_MAX = RENDER_ERROR, | 33 RENDER_EVENT_MAX = RENDER_ERROR, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 | 121 |
| 121 void AudioRendererImpl::DoPause_Locked() { | 122 void AudioRendererImpl::DoPause_Locked() { |
| 122 DCHECK(task_runner_->BelongsToCurrentThread()); | 123 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 123 lock_.AssertAcquired(); | 124 lock_.AssertAcquired(); |
| 124 | 125 |
| 125 if (sink_playing_) { | 126 if (sink_playing_) { |
| 126 { | 127 { |
| 127 base::AutoUnlock auto_unlock(lock_); | 128 base::AutoUnlock auto_unlock(lock_); |
| 128 sink_->Pause(); | 129 sink_->Pause(); |
| 129 } | 130 } |
| 131 buffered_audio_tracker_->AudioCallbackFired(0); | |
| 130 sink_playing_ = false; | 132 sink_playing_ = false; |
| 131 } | 133 } |
| 132 } | 134 } |
| 133 | 135 |
| 134 void AudioRendererImpl::Flush(const base::Closure& callback) { | 136 void AudioRendererImpl::Flush(const base::Closure& callback) { |
| 135 DCHECK(task_runner_->BelongsToCurrentThread()); | 137 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 136 | 138 |
| 137 base::AutoLock auto_lock(lock_); | 139 base::AutoLock auto_lock(lock_); |
| 138 DCHECK_EQ(state_, kPaused); | 140 DCHECK_EQ(state_, kPaused); |
| 139 DCHECK(flush_cb_.is_null()); | 141 DCHECK(flush_cb_.is_null()); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); | 283 const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); |
| 282 audio_parameters_.Reset(hw_params.format(), | 284 audio_parameters_.Reset(hw_params.format(), |
| 283 hw_params.channel_layout(), | 285 hw_params.channel_layout(), |
| 284 hw_params.channels(), | 286 hw_params.channels(), |
| 285 hw_params.input_channels(), | 287 hw_params.input_channels(), |
| 286 hw_params.sample_rate(), | 288 hw_params.sample_rate(), |
| 287 hw_params.bits_per_sample(), | 289 hw_params.bits_per_sample(), |
| 288 hardware_config_->GetHighLatencyBufferSize()); | 290 hardware_config_->GetHighLatencyBufferSize()); |
| 289 } | 291 } |
| 290 | 292 |
| 293 buffered_audio_tracker_.reset( | |
| 294 new BufferedAudioTracker(audio_parameters_.sample_rate())); | |
| 295 | |
| 291 audio_buffer_stream_.Initialize( | 296 audio_buffer_stream_.Initialize( |
| 292 stream, | 297 stream, |
| 293 statistics_cb, | 298 statistics_cb, |
| 294 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, | 299 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, |
| 295 weak_factory_.GetWeakPtr())); | 300 weak_factory_.GetWeakPtr())); |
| 296 } | 301 } |
| 297 | 302 |
| 298 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { | 303 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { |
| 299 DCHECK(task_runner_->BelongsToCurrentThread()); | 304 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 300 | 305 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 DCHECK_EQ(state_, kPrerolling); | 564 DCHECK_EQ(state_, kPrerolling); |
| 560 return buffer && !buffer->end_of_stream() && | 565 return buffer && !buffer->end_of_stream() && |
| 561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; | 566 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; |
| 562 } | 567 } |
| 563 | 568 |
| 564 int AudioRendererImpl::Render(AudioBus* audio_bus, | 569 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 565 int audio_delay_milliseconds) { | 570 int audio_delay_milliseconds) { |
| 566 const int requested_frames = audio_bus->frames(); | 571 const int requested_frames = audio_bus->frames(); |
| 567 base::TimeDelta current_time = kNoTimestamp(); | 572 base::TimeDelta current_time = kNoTimestamp(); |
| 568 base::TimeDelta max_time = kNoTimestamp(); | 573 base::TimeDelta max_time = kNoTimestamp(); |
| 569 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | |
| 570 audio_delay_milliseconds); | |
| 571 | 574 |
| 572 int frames_written = 0; | 575 int frames_written = 0; |
| 573 base::Closure underflow_cb; | 576 base::Closure underflow_cb; |
| 574 { | 577 { |
| 575 base::AutoLock auto_lock(lock_); | 578 base::AutoLock auto_lock(lock_); |
| 576 | 579 |
| 580 // Convert milliseconds of delay into frames of delay. | |
| 581 buffered_audio_tracker_->AudioCallbackFired(static_cast<int>( | |
| 582 static_cast<float>(audio_delay_milliseconds) / | |
| 583 base::Time::kMillisecondsPerSecond * audio_parameters_.sample_rate())); | |
| 584 | |
| 577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 585 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
| 578 if (!algorithm_) | 586 if (!algorithm_) { |
| 587 buffered_audio_tracker_->WroteSilence(requested_frames); | |
|
scherkus (not reviewing)
2014/04/29 17:22:06
alternatively, we can delete buffered_audio_tracke
DaleCurtis
2014/04/29 17:55:54
I don't think you need to track this. algorithm_ s
| |
| 579 return 0; | 588 return 0; |
| 589 } | |
| 580 | 590 |
| 581 float playback_rate = algorithm_->playback_rate(); | 591 float playback_rate = algorithm_->playback_rate(); |
| 582 if (playback_rate == 0) | 592 if (playback_rate == 0) { |
| 593 buffered_audio_tracker_->WroteSilence(requested_frames); | |
| 583 return 0; | 594 return 0; |
| 595 } | |
| 584 | 596 |
| 585 // Mute audio by returning 0 when not playing. | 597 // Mute audio by returning 0 when not playing. |
| 586 if (state_ != kPlaying) | 598 if (state_ != kPlaying) { |
| 599 buffered_audio_tracker_->WroteSilence(requested_frames); | |
| 587 return 0; | 600 return 0; |
| 601 } | |
| 588 | 602 |
| 589 // We use the following conditions to determine end of playback: | 603 // We use the following conditions to determine end of playback: |
| 590 // 1) Algorithm can not fill the audio callback buffer | 604 // 1) Algorithm can not fill the audio callback buffer |
| 591 // 2) We received an end of stream buffer | 605 // 2) We received an end of stream buffer |
| 592 // 3) We haven't already signalled that we've ended | 606 // 3) We haven't already signalled that we've ended |
| 593 // 4) Our estimated earliest end time has expired | 607 // 4) Our estimated earliest end time has expired |
| 594 // | 608 // |
| 595 // TODO(enal): we should replace (4) with a check that the browser has no | 609 // TODO(enal): we should replace (4) with a check that the browser has no |
| 596 // more audio data or at least use a delayed callback. | 610 // more audio data or at least use a delayed callback. |
| 597 // | 611 // |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 620 // |earliest_end_time_|. | 634 // |earliest_end_time_|. |
| 621 } | 635 } |
| 622 } | 636 } |
| 623 | 637 |
| 624 if (CanRead_Locked()) { | 638 if (CanRead_Locked()) { |
| 625 task_runner_->PostTask(FROM_HERE, | 639 task_runner_->PostTask(FROM_HERE, |
| 626 base::Bind(&AudioRendererImpl::AttemptRead, | 640 base::Bind(&AudioRendererImpl::AttemptRead, |
| 627 weak_factory_.GetWeakPtr())); | 641 weak_factory_.GetWeakPtr())); |
| 628 } | 642 } |
| 629 | 643 |
| 630 // Adjust the delay according to playback rate. | 644 // Update buffered audio stats. |
| 631 base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds( | 645 base::TimeDelta playback_delay = buffered_audio_tracker_->BufferedTime(); |
| 632 ceil(playback_delay.InMicroseconds() * playback_rate)); | 646 if (frames_written > 0) |
| 647 buffered_audio_tracker_->WroteAudio(frames_written, playback_rate); | |
| 648 if (frames_written < requested_frames) | |
| 649 buffered_audio_tracker_->WroteSilence(requested_frames - frames_written); | |
| 633 | 650 |
| 634 // The |audio_time_buffered_| is the ending timestamp of the last frame | 651 // The |audio_time_buffered_| is the ending timestamp of the last frame |
| 635 // buffered at the audio device. |playback_delay| is the amount of time | 652 // buffered at the audio device. |playback_delay| is the amount of time |
| 636 // buffered at the audio device. The current time can be computed by their | 653 // buffered at the audio device. The current time can be computed by their |
| 637 // difference. | 654 // difference. |
| 638 if (audio_time_buffered_ != kNoTimestamp()) { | 655 if (audio_time_buffered_ != kNoTimestamp()) { |
| 639 base::TimeDelta previous_time = current_time_; | 656 base::TimeDelta previous_time = current_time_; |
| 640 current_time_ = audio_time_buffered_ - adjusted_playback_delay; | 657 current_time_ = audio_time_buffered_ - playback_delay; |
| 641 | 658 |
| 642 // Time can change in one of two ways: | 659 // Time can change in one of two ways: |
| 643 // 1) The time of the audio data at the audio device changed, or | 660 // 1) The time of the audio data at the audio device changed, or |
| 644 // 2) The playback delay value has changed | 661 // 2) The playback delay value has changed |
| 645 // | 662 // |
| 646 // We only want to set |current_time| (and thus execute |time_cb_|) if | 663 // We only want to set |current_time| (and thus execute |time_cb_|) if |
| 647 // time has progressed and we haven't signaled end of stream yet. | 664 // time has progressed and we haven't signaled end of stream yet. |
| 648 // | 665 // |
| 649 // Why? The current latency of the system results in getting the last call | 666 // Why? The current latency of the system results in getting the last call |
| 650 // to FillBuffer() later than we'd like, which delays firing the 'ended' | 667 // to FillBuffer() later than we'd like, which delays firing the 'ended' |
| 651 // event, which delays the looping/trigging performance of short sound | 668 // event, which delays the looping/trigging performance of short sound |
| 652 // effects. | 669 // effects. |
| 653 // | 670 // |
| 654 // TODO(scherkus): revisit this and switch back to relying on playback | 671 // TODO(scherkus): revisit this and switch back to relying on playback |
| 655 // delay after we've revamped our audio IPC subsystem. | 672 // delay after we've revamped our audio IPC subsystem. |
| 656 if (current_time_ > previous_time && !rendered_end_of_stream_) { | 673 if (current_time_ > previous_time && !rendered_end_of_stream_) { |
| 657 current_time = current_time_; | 674 current_time = current_time_; |
| 658 } | 675 } |
| 659 } else if (frames_written > 0) { | 676 } else if (frames_written > 0) { |
| 660 // Nothing has been buffered yet, so use the first buffer's timestamp. | 677 // Nothing has been buffered yet, so use the first buffer's timestamp. |
| 661 DCHECK(time_before_filling != kNoTimestamp()); | 678 DCHECK(time_before_filling != kNoTimestamp()); |
| 662 current_time_ = current_time = | 679 current_time_ = current_time = time_before_filling - playback_delay; |
| 663 time_before_filling - adjusted_playback_delay; | |
| 664 } | 680 } |
| 665 | 681 |
| 666 // The call to FillBuffer() on |algorithm_| has increased the amount of | 682 // The call to FillBuffer() on |algorithm_| has increased the amount of |
| 667 // buffered audio data. Update the new amount of time buffered. | 683 // buffered audio data. Update the new amount of time buffered. |
| 668 max_time = algorithm_->GetTime(); | 684 max_time = algorithm_->GetTime(); |
| 669 audio_time_buffered_ = max_time; | 685 audio_time_buffered_ = max_time; |
| 670 | 686 |
| 671 if (frames_written > 0) { | 687 if (frames_written > 0) { |
| 672 UpdateEarliestEndTime_Locked( | 688 UpdateEarliestEndTime_Locked( |
| 673 frames_written, playback_delay, now_cb_.Run()); | 689 frames_written, playback_delay, now_cb_.Run()); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 DCHECK(expecting_config_changes_); | 779 DCHECK(expecting_config_changes_); |
| 764 buffer_converter_->ResetTimestampState(); | 780 buffer_converter_->ResetTimestampState(); |
| 765 // Drain flushed buffers from the converter so the AudioSplicer receives all | 781 // Drain flushed buffers from the converter so the AudioSplicer receives all |
| 766 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | 782 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should |
| 767 // only appear after config changes, AddInput() should never fail here. | 783 // only appear after config changes, AddInput() should never fail here. |
| 768 while (buffer_converter_->HasNextBuffer()) | 784 while (buffer_converter_->HasNextBuffer()) |
| 769 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | 785 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
| 770 } | 786 } |
| 771 | 787 |
| 772 } // namespace media | 788 } // namespace media |
| OLD | NEW |