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/audio_clock.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 17 matching lines...) Expand all Loading... | |
50 audio_buffer_stream_(task_runner, | 51 audio_buffer_stream_(task_runner, |
51 decoders.Pass(), | 52 decoders.Pass(), |
52 set_decryptor_ready_cb), | 53 set_decryptor_ready_cb), |
53 hardware_config_(hardware_config), | 54 hardware_config_(hardware_config), |
54 now_cb_(base::Bind(&base::TimeTicks::Now)), | 55 now_cb_(base::Bind(&base::TimeTicks::Now)), |
55 state_(kUninitialized), | 56 state_(kUninitialized), |
56 sink_playing_(false), | 57 sink_playing_(false), |
57 pending_read_(false), | 58 pending_read_(false), |
58 received_end_of_stream_(false), | 59 received_end_of_stream_(false), |
59 rendered_end_of_stream_(false), | 60 rendered_end_of_stream_(false), |
60 audio_time_buffered_(kNoTimestamp()), | |
61 current_time_(kNoTimestamp()), | |
62 underflow_disabled_(false), | 61 underflow_disabled_(false), |
63 preroll_aborted_(false), | 62 preroll_aborted_(false), |
64 weak_factory_(this) { | 63 weak_factory_(this) { |
65 audio_buffer_stream_.set_splice_observer(base::Bind( | 64 audio_buffer_stream_.set_splice_observer(base::Bind( |
66 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); | 65 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); |
67 audio_buffer_stream_.set_config_change_observer(base::Bind( | 66 audio_buffer_stream_.set_config_change_observer(base::Bind( |
68 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 67 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
69 } | 68 } |
70 | 69 |
71 AudioRendererImpl::~AudioRendererImpl() { | 70 AudioRendererImpl::~AudioRendererImpl() { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 void AudioRendererImpl::ResetDecoderDone() { | 161 void AudioRendererImpl::ResetDecoderDone() { |
163 DCHECK(task_runner_->BelongsToCurrentThread()); | 162 DCHECK(task_runner_->BelongsToCurrentThread()); |
164 { | 163 { |
165 base::AutoLock auto_lock(lock_); | 164 base::AutoLock auto_lock(lock_); |
166 if (state_ == kStopped) | 165 if (state_ == kStopped) |
167 return; | 166 return; |
168 | 167 |
169 DCHECK_EQ(state_, kPaused); | 168 DCHECK_EQ(state_, kPaused); |
170 DCHECK(!flush_cb_.is_null()); | 169 DCHECK(!flush_cb_.is_null()); |
171 | 170 |
172 audio_time_buffered_ = kNoTimestamp(); | 171 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); |
DaleCurtis
2014/04/30 20:36:33
Kind of stinks to allocate a whole new object. You
scherkus (not reviewing)
2014/05/02 19:26:05
Considering the low frequency of this operation I
| |
173 current_time_ = kNoTimestamp(); | |
174 received_end_of_stream_ = false; | 172 received_end_of_stream_ = false; |
175 rendered_end_of_stream_ = false; | 173 rendered_end_of_stream_ = false; |
176 preroll_aborted_ = false; | 174 preroll_aborted_ = false; |
177 | 175 |
178 earliest_end_time_ = now_cb_.Run(); | 176 earliest_end_time_ = now_cb_.Run(); |
179 splicer_->Reset(); | 177 splicer_->Reset(); |
180 if (buffer_converter_) | 178 if (buffer_converter_) |
181 buffer_converter_->Reset(); | 179 buffer_converter_->Reset(); |
182 algorithm_->FlushBuffers(); | 180 algorithm_->FlushBuffers(); |
183 } | 181 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); | 279 const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); |
282 audio_parameters_.Reset(hw_params.format(), | 280 audio_parameters_.Reset(hw_params.format(), |
283 hw_params.channel_layout(), | 281 hw_params.channel_layout(), |
284 hw_params.channels(), | 282 hw_params.channels(), |
285 hw_params.input_channels(), | 283 hw_params.input_channels(), |
286 hw_params.sample_rate(), | 284 hw_params.sample_rate(), |
287 hw_params.bits_per_sample(), | 285 hw_params.bits_per_sample(), |
288 hardware_config_->GetHighLatencyBufferSize()); | 286 hardware_config_->GetHighLatencyBufferSize()); |
289 } | 287 } |
290 | 288 |
289 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); | |
290 | |
291 audio_buffer_stream_.Initialize( | 291 audio_buffer_stream_.Initialize( |
292 stream, | 292 stream, |
293 statistics_cb, | 293 statistics_cb, |
294 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, | 294 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, |
295 weak_factory_.GetWeakPtr())); | 295 weak_factory_.GetWeakPtr())); |
296 } | 296 } |
297 | 297 |
298 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { | 298 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { |
299 DCHECK(task_runner_->BelongsToCurrentThread()); | 299 DCHECK(task_runner_->BelongsToCurrentThread()); |
300 | 300 |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
557 bool AudioRendererImpl::IsBeforePrerollTime( | 557 bool AudioRendererImpl::IsBeforePrerollTime( |
558 const scoped_refptr<AudioBuffer>& buffer) { | 558 const scoped_refptr<AudioBuffer>& buffer) { |
559 DCHECK_EQ(state_, kPrerolling); | 559 DCHECK_EQ(state_, kPrerolling); |
560 return buffer && !buffer->end_of_stream() && | 560 return buffer && !buffer->end_of_stream() && |
561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; | 561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; |
562 } | 562 } |
563 | 563 |
564 int AudioRendererImpl::Render(AudioBus* audio_bus, | 564 int AudioRendererImpl::Render(AudioBus* audio_bus, |
565 int audio_delay_milliseconds) { | 565 int audio_delay_milliseconds) { |
566 const int requested_frames = audio_bus->frames(); | 566 const int requested_frames = audio_bus->frames(); |
567 base::TimeDelta current_time = kNoTimestamp(); | |
568 base::TimeDelta max_time = kNoTimestamp(); | |
569 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 567 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( |
570 audio_delay_milliseconds); | 568 audio_delay_milliseconds); |
571 | 569 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
570 audio_parameters_.sample_rate()); | |
572 int frames_written = 0; | 571 int frames_written = 0; |
572 base::Closure time_cb; | |
573 base::Closure underflow_cb; | 573 base::Closure underflow_cb; |
574 { | 574 { |
575 base::AutoLock auto_lock(lock_); | 575 base::AutoLock auto_lock(lock_); |
576 | 576 |
577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
578 if (!algorithm_) | 578 if (!algorithm_) { |
579 audio_clock_->WroteSilence(requested_frames, delay_frames); | |
DaleCurtis
2014/04/30 20:36:33
This should only be true after Stop() has been cal
scherkus (not reviewing)
2014/05/02 19:26:05
Will leave it in for now ... I suspect this functi
| |
579 return 0; | 580 return 0; |
581 } | |
580 | 582 |
581 float playback_rate = algorithm_->playback_rate(); | 583 float playback_rate = algorithm_->playback_rate(); |
582 if (playback_rate == 0) | 584 if (playback_rate == 0) { |
585 audio_clock_->WroteSilence(requested_frames, delay_frames); | |
583 return 0; | 586 return 0; |
587 } | |
584 | 588 |
585 // Mute audio by returning 0 when not playing. | 589 // Mute audio by returning 0 when not playing. |
586 if (state_ != kPlaying) | 590 if (state_ != kPlaying) { |
591 audio_clock_->WroteSilence(requested_frames, delay_frames); | |
587 return 0; | 592 return 0; |
593 } | |
588 | 594 |
589 // We use the following conditions to determine end of playback: | 595 // We use the following conditions to determine end of playback: |
590 // 1) Algorithm can not fill the audio callback buffer | 596 // 1) Algorithm can not fill the audio callback buffer |
591 // 2) We received an end of stream buffer | 597 // 2) We received an end of stream buffer |
592 // 3) We haven't already signalled that we've ended | 598 // 3) We haven't already signalled that we've ended |
593 // 4) Our estimated earliest end time has expired | 599 // 4) Our estimated earliest end time has expired |
594 // | 600 // |
595 // TODO(enal): we should replace (4) with a check that the browser has no | 601 // 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. | 602 // more audio data or at least use a delayed callback. |
597 // | 603 // |
598 // We use the following conditions to determine underflow: | 604 // We use the following conditions to determine underflow: |
599 // 1) Algorithm can not fill the audio callback buffer | 605 // 1) Algorithm can not fill the audio callback buffer |
600 // 2) We have NOT received an end of stream buffer | 606 // 2) We have NOT received an end of stream buffer |
601 // 3) We are in the kPlaying state | 607 // 3) We are in the kPlaying state |
602 // | 608 // |
603 // Otherwise the buffer has data we can send to the device. | 609 // Otherwise the buffer has data we can send to the device. |
604 const base::TimeDelta time_before_filling = algorithm_->GetTime(); | 610 const base::TimeDelta media_timestamp_before_filling = |
611 audio_clock_->CurrentMediaTimestamp(); | |
605 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); | 612 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); |
613 audio_clock_->WroteAudio( | |
614 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); | |
615 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); | |
616 | |
606 if (frames_written == 0) { | 617 if (frames_written == 0) { |
607 const base::TimeTicks now = now_cb_.Run(); | 618 const base::TimeTicks now = now_cb_.Run(); |
608 | 619 |
609 if (received_end_of_stream_ && !rendered_end_of_stream_ && | 620 if (received_end_of_stream_ && !rendered_end_of_stream_ && |
610 now >= earliest_end_time_) { | 621 now >= earliest_end_time_) { |
scherkus (not reviewing)
2014/04/30 19:13:58
I know more of this code can get cleaned up (e.g.,
DaleCurtis
2014/04/30 20:36:33
I agree. Is it possible to get rid of earliest_end
| |
611 rendered_end_of_stream_ = true; | 622 rendered_end_of_stream_ = true; |
612 ended_cb_.Run(); | 623 ended_cb_.Run(); |
613 } else if (!received_end_of_stream_ && state_ == kPlaying && | 624 } else if (!received_end_of_stream_ && state_ == kPlaying && |
614 !underflow_disabled_) { | 625 !underflow_disabled_) { |
615 ChangeState_Locked(kUnderflow); | 626 ChangeState_Locked(kUnderflow); |
616 underflow_cb = underflow_cb_; | 627 underflow_cb = underflow_cb_; |
617 } else { | 628 } else { |
618 // We can't write any data this cycle. For example, we may have | 629 // We can't write any data this cycle. For example, we may have |
619 // sent all available data to the audio device while not reaching | 630 // sent all available data to the audio device while not reaching |
620 // |earliest_end_time_|. | 631 // |earliest_end_time_|. |
621 } | 632 } |
622 } | 633 } |
623 | 634 |
624 if (CanRead_Locked()) { | 635 if (CanRead_Locked()) { |
625 task_runner_->PostTask(FROM_HERE, | 636 task_runner_->PostTask(FROM_HERE, |
DaleCurtis
2014/04/30 20:36:33
Really this should be TryPostTask() since PostTask
| |
626 base::Bind(&AudioRendererImpl::AttemptRead, | 637 base::Bind(&AudioRendererImpl::AttemptRead, |
627 weak_factory_.GetWeakPtr())); | 638 weak_factory_.GetWeakPtr())); |
628 } | 639 } |
629 | 640 |
630 // Adjust the delay according to playback rate. | 641 // Time can change in one of two ways: |
631 base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds( | 642 // 1) The time of the audio data at the audio device changed, or |
632 ceil(playback_delay.InMicroseconds() * playback_rate)); | 643 // 2) The playback delay value has changed |
633 | 644 // |
634 // The |audio_time_buffered_| is the ending timestamp of the last frame | 645 // We only want to execute |time_cb_| if time has progressed and we haven't |
635 // buffered at the audio device. |playback_delay| is the amount of time | 646 // signaled end of stream yet. |
636 // buffered at the audio device. The current time can be computed by their | 647 // |
637 // difference. | 648 // Why? The current latency of the system results in getting the last call |
638 if (audio_time_buffered_ != kNoTimestamp()) { | 649 // to FillBuffer() later than we'd like, which delays firing the 'ended' |
639 base::TimeDelta previous_time = current_time_; | 650 // event, which delays the looping/trigging performance of short sound |
640 current_time_ = audio_time_buffered_ - adjusted_playback_delay; | 651 // effects. |
641 | 652 // |
642 // Time can change in one of two ways: | 653 // TODO(scherkus): revisit this and switch back to relying on playback |
643 // 1) The time of the audio data at the audio device changed, or | 654 // delay after we've revamped our audio IPC subsystem. |
scherkus (not reviewing)
2014/04/30 19:13:58
I'm not sure how much of this whole comment block
DaleCurtis
2014/04/30 20:36:33
Agreed.
scherkus (not reviewing)
2014/05/02 19:26:05
Trimmed it down.
| |
644 // 2) The playback delay value has changed | 655 if (media_timestamp_before_filling != |
645 // | 656 audio_clock_->CurrentMediaTimestamp() && |
646 // We only want to set |current_time| (and thus execute |time_cb_|) if | 657 !rendered_end_of_stream_) { |
647 // time has progressed and we haven't signaled end of stream yet. | 658 time_cb = base::Bind(time_cb_, |
648 // | 659 audio_clock_->CurrentMediaTimestamp(), |
649 // Why? The current latency of the system results in getting the last call | 660 audio_clock_->LastEndpointTimestamp()); |
650 // to FillBuffer() later than we'd like, which delays firing the 'ended' | |
651 // event, which delays the looping/trigging performance of short sound | |
652 // effects. | |
653 // | |
654 // TODO(scherkus): revisit this and switch back to relying on playback | |
655 // delay after we've revamped our audio IPC subsystem. | |
656 if (current_time_ > previous_time && !rendered_end_of_stream_) { | |
657 current_time = current_time_; | |
658 } | |
659 } else if (frames_written > 0) { | |
660 // Nothing has been buffered yet, so use the first buffer's timestamp. | |
661 DCHECK(time_before_filling != kNoTimestamp()); | |
662 current_time_ = current_time = | |
663 time_before_filling - adjusted_playback_delay; | |
664 } | 661 } |
665 | 662 |
666 // The call to FillBuffer() on |algorithm_| has increased the amount of | |
667 // buffered audio data. Update the new amount of time buffered. | |
668 max_time = algorithm_->GetTime(); | |
669 audio_time_buffered_ = max_time; | |
670 | |
671 if (frames_written > 0) { | 663 if (frames_written > 0) { |
672 UpdateEarliestEndTime_Locked( | 664 UpdateEarliestEndTime_Locked( |
673 frames_written, playback_delay, now_cb_.Run()); | 665 frames_written, playback_delay, now_cb_.Run()); |
674 } | 666 } |
675 } | 667 } |
676 | 668 |
677 if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) | 669 if (!time_cb.is_null()) |
678 time_cb_.Run(current_time, max_time); | 670 time_cb.Run(); |
679 | 671 |
680 if (!underflow_cb.is_null()) | 672 if (!underflow_cb.is_null()) |
681 underflow_cb.Run(); | 673 underflow_cb.Run(); |
682 | 674 |
683 DCHECK_LE(frames_written, requested_frames); | 675 DCHECK_LE(frames_written, requested_frames); |
684 return frames_written; | 676 return frames_written; |
685 } | 677 } |
686 | 678 |
687 void AudioRendererImpl::UpdateEarliestEndTime_Locked( | 679 void AudioRendererImpl::UpdateEarliestEndTime_Locked( |
688 int frames_filled, const base::TimeDelta& playback_delay, | 680 int frames_filled, const base::TimeDelta& playback_delay, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
763 DCHECK(expecting_config_changes_); | 755 DCHECK(expecting_config_changes_); |
764 buffer_converter_->ResetTimestampState(); | 756 buffer_converter_->ResetTimestampState(); |
765 // Drain flushed buffers from the converter so the AudioSplicer receives all | 757 // Drain flushed buffers from the converter so the AudioSplicer receives all |
766 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | 758 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should |
767 // only appear after config changes, AddInput() should never fail here. | 759 // only appear after config changes, AddInput() should never fail here. |
768 while (buffer_converter_->HasNextBuffer()) | 760 while (buffer_converter_->HasNextBuffer()) |
769 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | 761 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
770 } | 762 } |
771 | 763 |
772 } // namespace media | 764 } // namespace media |
OLD | NEW |