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

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

Issue 379343005: Introduce media::TimeSource. (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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698