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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
65 audio_buffer_stream_.set_config_change_observer(base::Bind( | 65 audio_buffer_stream_.set_config_change_observer(base::Bind( |
66 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 66 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
67 } | 67 } |
68 | 68 |
69 AudioRendererImpl::~AudioRendererImpl() { | 69 AudioRendererImpl::~AudioRendererImpl() { |
70 // Stop() should have been called and |algorithm_| should have been destroyed. | 70 // Stop() should have been called and |algorithm_| should have been destroyed. |
71 DCHECK(state_ == kUninitialized || state_ == kStopped); | 71 DCHECK(state_ == kUninitialized || state_ == kStopped); |
72 DCHECK(!algorithm_.get()); | 72 DCHECK(!algorithm_.get()); |
73 } | 73 } |
74 | 74 |
75 void AudioRendererImpl::StartRendering() { | 75 void AudioRendererImpl::StartTicking() { |
76 DVLOG(1) << __FUNCTION__; | 76 DVLOG(1) << __FUNCTION__; |
77 DCHECK(task_runner_->BelongsToCurrentThread()); | 77 DCHECK(task_runner_->BelongsToCurrentThread()); |
78 DCHECK(!rendering_); | 78 DCHECK(!rendering_); |
79 rendering_ = true; | 79 rendering_ = true; |
80 | 80 |
81 base::AutoLock auto_lock(lock_); | 81 base::AutoLock auto_lock(lock_); |
82 // Wait for an eventual call to SetPlaybackRate() to start rendering. | 82 // Wait for an eventual call to SetPlaybackRate() to start rendering. |
83 if (algorithm_->playback_rate() == 0) { | 83 if (algorithm_->playback_rate() == 0) { |
84 DCHECK(!sink_playing_); | 84 DCHECK(!sink_playing_); |
85 return; | 85 return; |
86 } | 86 } |
87 | 87 |
88 StartRendering_Locked(); | 88 StartRendering_Locked(); |
89 } | 89 } |
90 | 90 |
91 void AudioRendererImpl::StartRendering_Locked() { | 91 void AudioRendererImpl::StartRendering_Locked() { |
92 DVLOG(1) << __FUNCTION__; | 92 DVLOG(1) << __FUNCTION__; |
93 DCHECK(task_runner_->BelongsToCurrentThread()); | 93 DCHECK(task_runner_->BelongsToCurrentThread()); |
94 DCHECK_EQ(state_, kPlaying); | 94 DCHECK_EQ(state_, kPlaying); |
95 DCHECK(!sink_playing_); | 95 DCHECK(!sink_playing_); |
96 DCHECK_NE(algorithm_->playback_rate(), 0); | 96 DCHECK_NE(algorithm_->playback_rate(), 0); |
97 lock_.AssertAcquired(); | 97 lock_.AssertAcquired(); |
98 | 98 |
99 sink_playing_ = true; | 99 sink_playing_ = true; |
100 | 100 |
101 base::AutoUnlock auto_unlock(lock_); | 101 base::AutoUnlock auto_unlock(lock_); |
102 sink_->Play(); | 102 sink_->Play(); |
103 } | 103 } |
104 | 104 |
105 void AudioRendererImpl::StopRendering() { | 105 void AudioRendererImpl::StopTicking() { |
106 DVLOG(1) << __FUNCTION__; | 106 DVLOG(1) << __FUNCTION__; |
107 DCHECK(task_runner_->BelongsToCurrentThread()); | 107 DCHECK(task_runner_->BelongsToCurrentThread()); |
108 DCHECK(rendering_); | 108 DCHECK(rendering_); |
109 rendering_ = false; | 109 rendering_ = false; |
110 | 110 |
111 base::AutoLock auto_lock(lock_); | 111 base::AutoLock auto_lock(lock_); |
112 // Rendering should have already been stopped with a zero playback rate. | 112 // Rendering should have already been stopped with a zero playback rate. |
113 if (algorithm_->playback_rate() == 0) { | 113 if (algorithm_->playback_rate() == 0) { |
114 DCHECK(!sink_playing_); | 114 DCHECK(!sink_playing_); |
115 return; | 115 return; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
199 { | 199 { |
200 base::AutoLock auto_lock(lock_); | 200 base::AutoLock auto_lock(lock_); |
201 | 201 |
202 if (state_ == kStopped) { | 202 if (state_ == kStopped) { |
203 task_runner_->PostTask(FROM_HERE, callback); | 203 task_runner_->PostTask(FROM_HERE, callback); |
204 return; | 204 return; |
205 } | 205 } |
206 | 206 |
207 ChangeState_Locked(kStopped); | 207 ChangeState_Locked(kStopped); |
208 algorithm_.reset(); | 208 algorithm_.reset(); |
209 time_cb_.Reset(); | |
210 flush_cb_.Reset(); | 209 flush_cb_.Reset(); |
211 } | 210 } |
212 | 211 |
213 if (sink_) { | 212 if (sink_) { |
214 sink_->Stop(); | 213 sink_->Stop(); |
215 sink_ = NULL; | 214 sink_ = NULL; |
216 } | 215 } |
217 | 216 |
218 audio_buffer_stream_.Stop(callback); | 217 audio_buffer_stream_.Stop(callback); |
219 } | 218 } |
220 | 219 |
221 void AudioRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 220 void AudioRendererImpl::StartPlaying() { |
222 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; | 221 DVLOG(1) << __FUNCTION__; |
223 DCHECK(task_runner_->BelongsToCurrentThread()); | 222 DCHECK(task_runner_->BelongsToCurrentThread()); |
224 | 223 |
225 base::AutoLock auto_lock(lock_); | 224 base::AutoLock auto_lock(lock_); |
226 DCHECK(!sink_playing_); | 225 DCHECK(!sink_playing_); |
227 DCHECK_EQ(state_, kFlushed); | 226 DCHECK_EQ(state_, kFlushed); |
228 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 227 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
229 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 228 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
230 | 229 |
231 ChangeState_Locked(kPlaying); | 230 ChangeState_Locked(kPlaying); |
231 AttemptRead_Locked(); | |
232 } | |
233 | |
234 void AudioRendererImpl::SetMediaTimestamp(base::TimeDelta timestamp) { | |
235 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; | |
236 DCHECK(!rendering_); | |
232 start_timestamp_ = timestamp; | 237 start_timestamp_ = timestamp; |
238 } | |
233 | 239 |
234 AttemptRead_Locked(); | 240 base::TimeDelta AudioRendererImpl::CurrentMediaTimestamp() { |
241 DVLOG(1) << __FUNCTION__; | |
242 DCHECK(task_runner_->BelongsToCurrentThread()); | |
243 | |
244 // TODO(scherkus): Take time since last updating |audio_clock_| into account. | |
xhwang
2014/07/12 06:36:44
Yeah, this will improve time accuracy, also solve
| |
245 base::AutoLock auto_lock(lock_); | |
246 base::TimeDelta timestamp = audio_clock_->CurrentMediaTimestamp(); | |
247 if (timestamp == kNoTimestamp()) | |
248 return start_timestamp_; | |
249 return timestamp; | |
235 } | 250 } |
236 | 251 |
237 void AudioRendererImpl::Initialize(DemuxerStream* stream, | 252 void AudioRendererImpl::Initialize(DemuxerStream* stream, |
238 const PipelineStatusCB& init_cb, | 253 const PipelineStatusCB& init_cb, |
239 const StatisticsCB& statistics_cb, | 254 const StatisticsCB& statistics_cb, |
240 const TimeCB& time_cb, | |
241 const BufferingStateCB& buffering_state_cb, | 255 const BufferingStateCB& buffering_state_cb, |
242 const base::Closure& ended_cb, | 256 const base::Closure& ended_cb, |
243 const PipelineStatusCB& error_cb) { | 257 const PipelineStatusCB& error_cb) { |
244 DCHECK(task_runner_->BelongsToCurrentThread()); | 258 DCHECK(task_runner_->BelongsToCurrentThread()); |
245 DCHECK(stream); | 259 DCHECK(stream); |
246 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 260 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
247 DCHECK(!init_cb.is_null()); | 261 DCHECK(!init_cb.is_null()); |
248 DCHECK(!statistics_cb.is_null()); | 262 DCHECK(!statistics_cb.is_null()); |
249 DCHECK(!time_cb.is_null()); | |
250 DCHECK(!buffering_state_cb.is_null()); | 263 DCHECK(!buffering_state_cb.is_null()); |
251 DCHECK(!ended_cb.is_null()); | 264 DCHECK(!ended_cb.is_null()); |
252 DCHECK(!error_cb.is_null()); | 265 DCHECK(!error_cb.is_null()); |
253 DCHECK_EQ(kUninitialized, state_); | 266 DCHECK_EQ(kUninitialized, state_); |
254 DCHECK(sink_); | 267 DCHECK(sink_); |
255 | 268 |
256 state_ = kInitializing; | 269 state_ = kInitializing; |
257 | 270 |
258 init_cb_ = init_cb; | 271 init_cb_ = init_cb; |
259 time_cb_ = time_cb; | |
260 buffering_state_cb_ = buffering_state_cb; | 272 buffering_state_cb_ = buffering_state_cb; |
261 ended_cb_ = ended_cb; | 273 ended_cb_ = ended_cb; |
262 error_cb_ = error_cb; | 274 error_cb_ = error_cb; |
263 | 275 |
264 expecting_config_changes_ = stream->SupportsConfigChanges(); | 276 expecting_config_changes_ = stream->SupportsConfigChanges(); |
265 if (!expecting_config_changes_) { | 277 if (!expecting_config_changes_) { |
266 // The actual buffer size is controlled via the size of the AudioBus | 278 // The actual buffer size is controlled via the size of the AudioBus |
267 // provided to Render(), so just choose something reasonable here for looks. | 279 // provided to Render(), so just choose something reasonable here for looks. |
268 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; | 280 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; |
269 audio_parameters_.Reset( | 281 audio_parameters_.Reset( |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 } | 557 } |
546 | 558 |
547 int AudioRendererImpl::Render(AudioBus* audio_bus, | 559 int AudioRendererImpl::Render(AudioBus* audio_bus, |
548 int audio_delay_milliseconds) { | 560 int audio_delay_milliseconds) { |
549 const int requested_frames = audio_bus->frames(); | 561 const int requested_frames = audio_bus->frames(); |
550 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 562 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( |
551 audio_delay_milliseconds); | 563 audio_delay_milliseconds); |
552 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 564 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
553 audio_parameters_.sample_rate()); | 565 audio_parameters_.sample_rate()); |
554 int frames_written = 0; | 566 int frames_written = 0; |
555 base::Closure time_cb; | |
556 { | 567 { |
557 base::AutoLock auto_lock(lock_); | 568 base::AutoLock auto_lock(lock_); |
558 | 569 |
559 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 570 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
560 if (!algorithm_) { | 571 if (!algorithm_) { |
561 audio_clock_->WroteSilence(requested_frames, delay_frames); | 572 audio_clock_->WroteSilence(requested_frames, delay_frames); |
562 return 0; | 573 return 0; |
563 } | 574 } |
564 | 575 |
565 float playback_rate = algorithm_->playback_rate(); | 576 float playback_rate = algorithm_->playback_rate(); |
(...skipping 13 matching lines...) Expand all Loading... | |
579 // 2) We received an end of stream buffer | 590 // 2) We received an end of stream buffer |
580 // 3) We haven't already signalled that we've ended | 591 // 3) We haven't already signalled that we've ended |
581 // 4) We've played all known audio data sent to hardware | 592 // 4) We've played all known audio data sent to hardware |
582 // | 593 // |
583 // We use the following conditions to determine underflow: | 594 // We use the following conditions to determine underflow: |
584 // 1) Algorithm can not fill the audio callback buffer | 595 // 1) Algorithm can not fill the audio callback buffer |
585 // 2) We have NOT received an end of stream buffer | 596 // 2) We have NOT received an end of stream buffer |
586 // 3) We are in the kPlaying state | 597 // 3) We are in the kPlaying state |
587 // | 598 // |
588 // Otherwise the buffer has data we can send to the device. | 599 // Otherwise the buffer has data we can send to the device. |
589 const base::TimeDelta media_timestamp_before_filling = | |
590 audio_clock_->CurrentMediaTimestamp(); | |
591 if (algorithm_->frames_buffered() > 0) { | 600 if (algorithm_->frames_buffered() > 0) { |
592 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); | 601 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); |
593 audio_clock_->WroteAudio( | 602 audio_clock_->WroteAudio( |
594 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); | 603 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); |
595 } | 604 } |
596 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); | 605 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); |
597 | 606 |
598 if (frames_written == 0) { | 607 if (frames_written == 0) { |
599 if (received_end_of_stream_ && !rendered_end_of_stream_ && | 608 if (received_end_of_stream_ && !rendered_end_of_stream_ && |
600 audio_clock_->CurrentMediaTimestamp() == | 609 audio_clock_->CurrentMediaTimestamp() == |
601 audio_clock_->last_endpoint_timestamp()) { | 610 audio_clock_->last_endpoint_timestamp()) { |
602 rendered_end_of_stream_ = true; | 611 rendered_end_of_stream_ = true; |
603 ended_cb_.Run(); | 612 ended_cb_.Run(); |
604 } else if (!received_end_of_stream_ && state_ == kPlaying) { | 613 } else if (!received_end_of_stream_ && state_ == kPlaying) { |
605 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | 614 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { |
606 algorithm_->IncreaseQueueCapacity(); | 615 algorithm_->IncreaseQueueCapacity(); |
607 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 616 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
608 } | 617 } |
609 } | 618 } |
610 } | 619 } |
611 | 620 |
612 if (CanRead_Locked()) { | 621 if (CanRead_Locked()) { |
613 task_runner_->PostTask(FROM_HERE, | 622 task_runner_->PostTask(FROM_HERE, |
614 base::Bind(&AudioRendererImpl::AttemptRead, | 623 base::Bind(&AudioRendererImpl::AttemptRead, |
615 weak_factory_.GetWeakPtr())); | 624 weak_factory_.GetWeakPtr())); |
616 } | 625 } |
617 | |
618 // We only want to execute |time_cb_| if time has progressed and we haven't | |
619 // signaled end of stream yet. | |
620 if (media_timestamp_before_filling != | |
621 audio_clock_->CurrentMediaTimestamp() && | |
622 !rendered_end_of_stream_) { | |
623 time_cb = base::Bind(time_cb_, | |
624 audio_clock_->CurrentMediaTimestamp(), | |
625 audio_clock_->last_endpoint_timestamp()); | |
626 } | |
627 } | 626 } |
628 | 627 |
629 if (!time_cb.is_null()) | |
630 task_runner_->PostTask(FROM_HERE, time_cb); | |
631 | |
632 DCHECK_LE(frames_written, requested_frames); | 628 DCHECK_LE(frames_written, requested_frames); |
633 return frames_written; | 629 return frames_written; |
634 } | 630 } |
635 | 631 |
636 void AudioRendererImpl::OnRenderError() { | 632 void AudioRendererImpl::OnRenderError() { |
637 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 633 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
638 // of trying to gracefully fall back to a fake sink. It's very likely | 634 // of trying to gracefully fall back to a fake sink. It's very likely |
639 // OnRenderError() should be removed and the audio stack handle errors without | 635 // OnRenderError() should be removed and the audio stack handle errors without |
640 // notifying clients. See http://crbug.com/234708 for details. | 636 // notifying clients. See http://crbug.com/234708 for details. |
641 HistogramRendererEvent(RENDER_ERROR); | 637 HistogramRendererEvent(RENDER_ERROR); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
699 << buffering_state; | 695 << buffering_state; |
700 DCHECK_NE(buffering_state_, buffering_state); | 696 DCHECK_NE(buffering_state_, buffering_state); |
701 lock_.AssertAcquired(); | 697 lock_.AssertAcquired(); |
702 buffering_state_ = buffering_state; | 698 buffering_state_ = buffering_state; |
703 | 699 |
704 task_runner_->PostTask(FROM_HERE, | 700 task_runner_->PostTask(FROM_HERE, |
705 base::Bind(buffering_state_cb_, buffering_state_)); | 701 base::Bind(buffering_state_cb_, buffering_state_)); |
706 } | 702 } |
707 | 703 |
708 } // namespace media | 704 } // namespace media |
OLD | NEW |