Chromium Code Reviews
Help | Chromium Project | Sign in
(771)

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

Issue 11275087: Move OnDecoderInitDone() from decoder to pipeline thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Missed AutoUnlock. Created 1 year, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
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
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/command_line.h" 14 #include "base/command_line.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/message_loop_proxy.h"
16 #include "media/audio/audio_util.h" 17 #include "media/audio/audio_util.h"
18 #include "media/base/bind_to_loop.h"
17 #include "media/base/demuxer_stream.h" 19 #include "media/base/demuxer_stream.h"
18 #include "media/base/media_switches.h" 20 #include "media/base/media_switches.h"
19 21
20 namespace media { 22 namespace media {
21 23
22 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) 24 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
23 : state_(kUninitialized), 25 : state_(kUninitialized),
24 pending_read_(false), 26 pending_read_(false),
25 received_end_of_stream_(false), 27 received_end_of_stream_(false),
26 rendered_end_of_stream_(false), 28 rendered_end_of_stream_(false),
27 audio_time_buffered_(kNoTimestamp()), 29 audio_time_buffered_(kNoTimestamp()),
28 current_time_(kNoTimestamp()), 30 current_time_(kNoTimestamp()),
29 bytes_per_frame_(0), 31 bytes_per_frame_(0),
30 stopped_(false), 32 stopped_(false),
31 sink_(sink), 33 sink_(sink),
32 underflow_disabled_(false), 34 underflow_disabled_(false),
33 preroll_aborted_(false) { 35 preroll_aborted_(false) {
36 // We're created on the render thread, but this thread checker is for another.
37 pipeline_thread_checker_.DetachFromThread();
34 } 38 }
35 39
36 void AudioRendererImpl::Play(const base::Closure& callback) { 40 void AudioRendererImpl::Play(const base::Closure& callback) {
41 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
37 { 42 {
38 base::AutoLock auto_lock(lock_); 43 base::AutoLock auto_lock(lock_);
39 DCHECK_EQ(kPaused, state_); 44 DCHECK_EQ(kPaused, state_);
40 state_ = kPlaying; 45 state_ = kPlaying;
41 callback.Run(); 46 callback.Run();
42 } 47 }
43 48
44 if (stopped_) 49 if (stopped_)
45 return; 50 return;
46 51
47 if (GetPlaybackRate() != 0.0f) { 52 if (GetPlaybackRate() != 0.0f) {
48 DoPlay(); 53 DoPlay();
49 } else { 54 } else {
50 DoPause(); 55 DoPause();
51 } 56 }
52 } 57 }
53 58
54 void AudioRendererImpl::DoPlay() { 59 void AudioRendererImpl::DoPlay() {
60 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
55 earliest_end_time_ = base::Time::Now(); 61 earliest_end_time_ = base::Time::Now();
56 sink_->Play(); 62 sink_->Play();
57 } 63 }
58 64
59 void AudioRendererImpl::Pause(const base::Closure& callback) { 65 void AudioRendererImpl::Pause(const base::Closure& callback) {
66 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
60 { 67 {
61 base::AutoLock auto_lock(lock_); 68 base::AutoLock auto_lock(lock_);
62 DCHECK(state_ == kPlaying || state_ == kUnderflow || 69 DCHECK(state_ == kPlaying || state_ == kUnderflow ||
63 state_ == kRebuffering); 70 state_ == kRebuffering);
64 pause_cb_ = callback; 71 pause_cb_ = callback;
65 state_ = kPaused; 72 state_ = kPaused;
66 73
67 // Pause only when we've completed our pending read. 74 // Pause only when we've completed our pending read.
68 if (!pending_read_) 75 if (!pending_read_)
69 base::ResetAndReturn(&pause_cb_).Run(); 76 base::ResetAndReturn(&pause_cb_).Run();
70 } 77 }
71 78
72 if (stopped_) 79 if (stopped_)
73 return; 80 return;
74 81
75 DoPause(); 82 DoPause();
76 } 83 }
77 84
78 void AudioRendererImpl::DoPause() { 85 void AudioRendererImpl::DoPause() {
86 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
79 sink_->Pause(false); 87 sink_->Pause(false);
80 } 88 }
81 89
82 void AudioRendererImpl::Flush(const base::Closure& callback) { 90 void AudioRendererImpl::Flush(const base::Closure& callback) {
91 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
83 decoder_->Reset(callback); 92 decoder_->Reset(callback);
84 } 93 }
85 94
86 void AudioRendererImpl::Stop(const base::Closure& callback) { 95 void AudioRendererImpl::Stop(const base::Closure& callback) {
96 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
87 DCHECK(!callback.is_null()); 97 DCHECK(!callback.is_null());
88 98
99 if (!stopped_) {
100 sink_->Stop();
101 stopped_ = true;
102 }
103
89 { 104 {
90 base::AutoLock auto_lock(lock_); 105 base::AutoLock auto_lock(lock_);
91 if (!stopped_) {
92 sink_->Stop();
93 stopped_ = true;
94 }
95
96 state_ = kStopped; 106 state_ = kStopped;
97 algorithm_.reset(NULL); 107 algorithm_.reset(NULL);
98 init_cb_.Reset(); 108 init_cb_.Reset();
99 underflow_cb_.Reset(); 109 underflow_cb_.Reset();
100 time_cb_.Reset(); 110 time_cb_.Reset();
101 } 111 }
102 112
103 callback.Run(); 113 callback.Run();
104 } 114 }
105 115
106 void AudioRendererImpl::Preroll(base::TimeDelta time, 116 void AudioRendererImpl::Preroll(base::TimeDelta time,
107 const PipelineStatusCB& cb) { 117 const PipelineStatusCB& cb) {
108 base::AutoLock auto_lock(lock_); 118 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
109 DCHECK_EQ(kPaused, state_);
110 DCHECK(!pending_read_) << "Pending read must complete before seeking";
111 DCHECK(pause_cb_.is_null());
112 DCHECK(preroll_cb_.is_null());
113 state_ = kPrerolling;
114 preroll_cb_ = cb;
115 preroll_timestamp_ = time;
116
117 // Throw away everything and schedule our reads.
118 audio_time_buffered_ = kNoTimestamp();
119 current_time_ = kNoTimestamp();
120 received_end_of_stream_ = false;
121 rendered_end_of_stream_ = false;
122 preroll_aborted_ = false;
123
124 // |algorithm_| will request more reads.
125 algorithm_->FlushBuffers();
126
127 if (stopped_) 119 if (stopped_)
128 return; 120 return;
129 121
122 {
123 base::AutoLock auto_lock(lock_);
124 DCHECK_EQ(kPaused, state_);
125 DCHECK(!pending_read_) << "Pending read must complete before seeking";
126 DCHECK(pause_cb_.is_null());
127 DCHECK(preroll_cb_.is_null());
128 state_ = kPrerolling;
129 preroll_cb_ = cb;
130 preroll_timestamp_ = time;
131
132 // Throw away everything and schedule our reads.
133 audio_time_buffered_ = kNoTimestamp();
134 current_time_ = kNoTimestamp();
135 received_end_of_stream_ = false;
136 rendered_end_of_stream_ = false;
137 preroll_aborted_ = false;
138
139 // |algorithm_| will request more reads.
140 algorithm_->FlushBuffers();
141 }
142
130 // Pause and flush the stream when we preroll to a new location. 143 // Pause and flush the stream when we preroll to a new location.
131 earliest_end_time_ = base::Time::Now(); 144 earliest_end_time_ = base::Time::Now();
132 sink_->Pause(true); 145 sink_->Pause(true);
133 } 146 }
134 147
135 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, 148 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream,
136 const AudioDecoderList& decoders, 149 const AudioDecoderList& decoders,
137 const PipelineStatusCB& init_cb, 150 const PipelineStatusCB& init_cb,
138 const StatisticsCB& statistics_cb, 151 const StatisticsCB& statistics_cb,
139 const base::Closure& underflow_cb, 152 const base::Closure& underflow_cb,
140 const TimeCB& time_cb, 153 const TimeCB& time_cb,
141 const base::Closure& ended_cb, 154 const base::Closure& ended_cb,
142 const base::Closure& disabled_cb, 155 const base::Closure& disabled_cb,
143 const PipelineStatusCB& error_cb) { 156 const PipelineStatusCB& error_cb) {
144 base::AutoLock auto_lock(lock_); 157 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
145 DCHECK(stream); 158 DCHECK(stream);
146 DCHECK(!decoders.empty()); 159 DCHECK(!decoders.empty());
147 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); 160 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO);
148 DCHECK(!init_cb.is_null()); 161 DCHECK(!init_cb.is_null());
149 DCHECK(!statistics_cb.is_null()); 162 DCHECK(!statistics_cb.is_null());
150 DCHECK(!underflow_cb.is_null()); 163 DCHECK(!underflow_cb.is_null());
151 DCHECK(!time_cb.is_null()); 164 DCHECK(!time_cb.is_null());
152 DCHECK(!ended_cb.is_null()); 165 DCHECK(!ended_cb.is_null());
153 DCHECK(!disabled_cb.is_null()); 166 DCHECK(!disabled_cb.is_null());
154 DCHECK(!error_cb.is_null()); 167 DCHECK(!error_cb.is_null());
155 DCHECK_EQ(kUninitialized, state_); 168 DCHECK_EQ(kUninitialized, state_);
156 169
157 init_cb_ = init_cb; 170 init_cb_ = init_cb;
158 statistics_cb_ = statistics_cb; 171 statistics_cb_ = statistics_cb;
159 underflow_cb_ = underflow_cb; 172 underflow_cb_ = underflow_cb;
160 time_cb_ = time_cb; 173 time_cb_ = time_cb;
161 ended_cb_ = ended_cb; 174 ended_cb_ = ended_cb;
162 disabled_cb_ = disabled_cb; 175 disabled_cb_ = disabled_cb;
163 error_cb_ = error_cb; 176 error_cb_ = error_cb;
164 177
165 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); 178 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders));
166 InitializeNextDecoder(stream, decoder_list.Pass()); 179 InitializeNextDecoder(stream, decoder_list.Pass());
167 } 180 }
168 181
169 void AudioRendererImpl::InitializeNextDecoder( 182 void AudioRendererImpl::InitializeNextDecoder(
170 const scoped_refptr<DemuxerStream>& demuxer_stream, 183 const scoped_refptr<DemuxerStream>& demuxer_stream,
171 scoped_ptr<AudioDecoderList> decoders) { 184 scoped_ptr<AudioDecoderList> decoders) {
172 lock_.AssertAcquired(); 185 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
173 DCHECK(!decoders->empty()); 186 DCHECK(!decoders->empty());
174 187
175 scoped_refptr<AudioDecoder> decoder = decoders->front(); 188 scoped_refptr<AudioDecoder> decoder = decoders->front();
176 decoders->pop_front(); 189 decoders->pop_front();
177 190
178 DCHECK(decoder); 191 DCHECK(decoder);
179 decoder_ = decoder; 192 decoder_ = decoder;
180
181 base::AutoUnlock auto_unlock(lock_);
182 decoder->Initialize( 193 decoder->Initialize(
183 demuxer_stream, 194 demuxer_stream, BindToLoop(base::MessageLoopProxy::current(), base::Bind(
184 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, 195 &AudioRendererImpl::OnDecoderInitDone, this, demuxer_stream,
185 demuxer_stream, 196 base::Passed(&decoders))),
186 base::Passed(&decoders)),
187 statistics_cb_); 197 statistics_cb_);
188 } 198 }
189 199
190 void AudioRendererImpl::OnDecoderInitDone( 200 void AudioRendererImpl::OnDecoderInitDone(
191 const scoped_refptr<DemuxerStream>& demuxer_stream, 201 const scoped_refptr<DemuxerStream>& demuxer_stream,
192 scoped_ptr<AudioDecoderList> decoders, 202 scoped_ptr<AudioDecoderList> decoders,
193 PipelineStatus status) { 203 PipelineStatus status) {
194 base::AutoLock auto_lock(lock_); 204 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
195 205
196 if (state_ == kStopped) { 206 if (state_ == kStopped) {
197 DCHECK(stopped_); 207 DCHECK(stopped_);
198 return; 208 return;
199 } 209 }
200 210
201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { 211 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) {
202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); 212 InitializeNextDecoder(demuxer_stream, decoders.Pass());
203 return; 213 return;
204 } 214 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 // purposes it's okay that this buffer size might lead to jitter since it's 270 // purposes it's okay that this buffer size might lead to jitter since it's
261 // not a multiple of the hardware buffer size. 271 // not a multiple of the hardware buffer size.
262 format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 272 format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
263 buffer_size = 2048; 273 buffer_size = 2048;
264 } 274 }
265 #endif 275 #endif
266 276
267 audio_parameters_ = AudioParameters( 277 audio_parameters_ = AudioParameters(
268 format, channel_layout, sample_rate, bits_per_channel, buffer_size); 278 format, channel_layout, sample_rate, bits_per_channel, buffer_size);
269 279
280 state_ = kPaused;
281
270 sink_->Initialize(audio_parameters_, this); 282 sink_->Initialize(audio_parameters_, this);
271 sink_->Start(); 283 sink_->Start();
272 284
273 state_ = kPaused;
274 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 285 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
275 } 286 }
276 287
277 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { 288 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) {
289 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
278 base::AutoLock auto_lock(lock_); 290 base::AutoLock auto_lock(lock_);
279 if (state_ == kUnderflow) { 291 if (state_ == kUnderflow) {
280 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we 292 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we
281 // shouldn't even reach the kUnderflow state to begin with. But for now 293 // shouldn't even reach the kUnderflow state to begin with. But for now
282 // we're just making sure that the audio buffer capacity (i.e. the 294 // we're just making sure that the audio buffer capacity (i.e. the
283 // number of bytes that need to be buffered for preroll to complete) 295 // number of bytes that need to be buffered for preroll to complete)
284 // does not increase due to an aborted preroll. 296 // does not increase due to an aborted preroll.
285 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) 297 // TODO(vrk): Fix this bug correctly! (crbug.com/151352)
286 if (buffer_more_audio && !preroll_aborted_) 298 if (buffer_more_audio && !preroll_aborted_)
287 algorithm_->IncreaseQueueCapacity(); 299 algorithm_->IncreaseQueueCapacity();
288 300
289 state_ = kRebuffering; 301 state_ = kRebuffering;
290 } 302 }
291 } 303 }
292 304
293 void AudioRendererImpl::SetVolume(float volume) { 305 void AudioRendererImpl::SetVolume(float volume) {
306 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
294 if (stopped_) 307 if (stopped_)
295 return; 308 return;
296 sink_->SetVolume(volume); 309 sink_->SetVolume(volume);
297 } 310 }
298 311
299 AudioRendererImpl::~AudioRendererImpl() { 312 AudioRendererImpl::~AudioRendererImpl() {
300 // Stop() should have been called and |algorithm_| should have been destroyed. 313 // Stop() should have been called and |algorithm_| should have been destroyed.
301 DCHECK(state_ == kUninitialized || state_ == kStopped); 314 DCHECK(state_ == kUninitialized || state_ == kStopped);
302 DCHECK(!algorithm_.get()); 315 DCHECK(!algorithm_.get());
303 } 316 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 382
370 void AudioRendererImpl::ScheduleRead_Locked() { 383 void AudioRendererImpl::ScheduleRead_Locked() {
371 lock_.AssertAcquired(); 384 lock_.AssertAcquired();
372 if (pending_read_ || state_ == kPaused) 385 if (pending_read_ || state_ == kPaused)
373 return; 386 return;
374 pending_read_ = true; 387 pending_read_ = true;
375 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this)); 388 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, this));
376 } 389 }
377 390
378 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { 391 void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
392 DCHECK(pipeline_thread_checker_.CalledOnValidThread());
379 DCHECK_LE(0.0f, playback_rate); 393 DCHECK_LE(0.0f, playback_rate);
380 394
381 if (!stopped_) { 395 if (!stopped_) {
382 // We have two cases here: 396 // We have two cases here:
383 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0 397 // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0
384 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0 398 // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0
385 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) { 399 if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) {
386 DoPlay(); 400 DoPlay();
387 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) { 401 } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) {
388 // Pause is easy, we can always pause. 402 // Pause is easy, we can always pause.
(...skipping 11 matching lines...) Expand all
400 } 414 }
401 415
402 bool AudioRendererImpl::IsBeforePrerollTime( 416 bool AudioRendererImpl::IsBeforePrerollTime(
403 const scoped_refptr<Buffer>& buffer) { 417 const scoped_refptr<Buffer>& buffer) {
404 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() && 418 return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() &&
405 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_; 419 (buffer->GetTimestamp() + buffer->GetDuration()) < preroll_timestamp_;
406 } 420 }
407 421
408 int AudioRendererImpl::Render(AudioBus* audio_bus, 422 int AudioRendererImpl::Render(AudioBus* audio_bus,
409 int audio_delay_milliseconds) { 423 int audio_delay_milliseconds) {
410 if (stopped_ || GetPlaybackRate() == 0.0f) { 424 if (stopped_ || GetPlaybackRate() == 0.0f) {
Ami Fischman 2012/11/01 19:57:01 Must not read stopped_ off pipeline thread.
Ami Fischman 2012/11/01 19:57:01 GetPlaybackRate() locks lock_ for its duration, bu
DaleCurtis 2012/11/01 22:02:59 Done.
DaleCurtis 2012/11/01 22:02:59 Fixed. Read once and saved for the duration of Ren
411 // Output silence if stopped. 425 // Output silence if stopped.
412 audio_bus->Zero(); 426 audio_bus->Zero();
413 return 0; 427 return 0;
414 } 428 }
415 429
416 // Adjust the playback delay. 430 // Adjust the playback delay.
417 base::TimeDelta request_delay = 431 base::TimeDelta request_delay =
418 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); 432 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
419 433
420 // Finally we need to adjust the delay according to playback rate. 434 // Finally we need to adjust the delay according to playback rate.
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 case kUnderflow: 612 case kUnderflow:
599 case kRebuffering: 613 case kRebuffering:
600 case kStopped: 614 case kStopped:
601 if (status != PIPELINE_OK) 615 if (status != PIPELINE_OK)
602 error_cb_.Run(status); 616 error_cb_.Run(status);
603 return; 617 return;
604 } 618 }
605 } 619 }
606 620
607 } // namespace media 621 } // namespace media
OLDNEW
« media/filters/audio_renderer_impl.h ('K') | « media/filters/audio_renderer_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1280:2d3e6564b7b6