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/message_loop/message_loop_proxy.h" | |
16 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.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_splicer.h" | 18 #include "media/base/audio_splicer.h" |
19 #include "media/base/bind_to_loop.h" | 19 #include "media/base/bind_to_loop.h" |
20 #include "media/base/demuxer_stream.h" | 20 #include "media/base/demuxer_stream.h" |
21 #include "media/filters/audio_decoder_selector.h" | 21 #include "media/filters/audio_decoder_selector.h" |
22 #include "media/filters/decrypting_demuxer_stream.h" | 22 #include "media/filters/decrypting_demuxer_stream.h" |
23 | 23 |
24 namespace media { | 24 namespace media { |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 enum AudioRendererEvent { | 28 enum AudioRendererEvent { |
29 INITIALIZED, | 29 INITIALIZED, |
30 RENDER_ERROR, | 30 RENDER_ERROR, |
31 MAX_EVENTS | 31 MAX_EVENTS |
32 }; | 32 }; |
33 | 33 |
34 void HistogramRendererEvent(AudioRendererEvent event) { | 34 void HistogramRendererEvent(AudioRendererEvent event) { |
35 UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS); | 35 UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS); |
36 } | 36 } |
37 | 37 |
38 } // namespace | 38 } // namespace |
39 | 39 |
40 AudioRendererImpl::AudioRendererImpl( | 40 AudioRendererImpl::AudioRendererImpl( |
41 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 41 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
42 media::AudioRendererSink* sink, | 42 media::AudioRendererSink* sink, |
43 ScopedVector<AudioDecoder> decoders, | 43 ScopedVector<AudioDecoder> decoders, |
44 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 44 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
45 bool increase_preroll_on_underflow) | 45 bool increase_preroll_on_underflow) |
46 : message_loop_(message_loop), | 46 : task_runner_(task_runner), |
47 weak_factory_(this), | 47 weak_factory_(this), |
48 sink_(sink), | 48 sink_(sink), |
49 decoder_selector_(new AudioDecoderSelector( | 49 decoder_selector_(new AudioDecoderSelector( |
50 message_loop, decoders.Pass(), set_decryptor_ready_cb)), | 50 task_runner, decoders.Pass(), set_decryptor_ready_cb)), |
51 now_cb_(base::Bind(&base::TimeTicks::Now)), | 51 now_cb_(base::Bind(&base::TimeTicks::Now)), |
52 state_(kUninitialized), | 52 state_(kUninitialized), |
53 sink_playing_(false), | 53 sink_playing_(false), |
54 pending_read_(false), | 54 pending_read_(false), |
55 received_end_of_stream_(false), | 55 received_end_of_stream_(false), |
56 rendered_end_of_stream_(false), | 56 rendered_end_of_stream_(false), |
57 audio_time_buffered_(kNoTimestamp()), | 57 audio_time_buffered_(kNoTimestamp()), |
58 current_time_(kNoTimestamp()), | 58 current_time_(kNoTimestamp()), |
59 underflow_disabled_(false), | 59 underflow_disabled_(false), |
60 increase_preroll_on_underflow_(increase_preroll_on_underflow), | 60 increase_preroll_on_underflow_(increase_preroll_on_underflow), |
61 preroll_aborted_(false) { | 61 preroll_aborted_(false) { |
62 } | 62 } |
63 | 63 |
64 AudioRendererImpl::~AudioRendererImpl() { | 64 AudioRendererImpl::~AudioRendererImpl() { |
65 // Stop() should have been called and |algorithm_| should have been destroyed. | 65 // Stop() should have been called and |algorithm_| should have been destroyed. |
66 DCHECK(state_ == kUninitialized || state_ == kStopped); | 66 DCHECK(state_ == kUninitialized || state_ == kStopped); |
67 DCHECK(!algorithm_.get()); | 67 DCHECK(!algorithm_.get()); |
68 } | 68 } |
69 | 69 |
70 void AudioRendererImpl::Play(const base::Closure& callback) { | 70 void AudioRendererImpl::Play(const base::Closure& callback) { |
71 DCHECK(message_loop_->BelongsToCurrentThread()); | 71 DCHECK(task_runner_->BelongsToCurrentThread()); |
72 | 72 |
73 base::AutoLock auto_lock(lock_); | 73 base::AutoLock auto_lock(lock_); |
74 DCHECK_EQ(state_, kPaused); | 74 DCHECK_EQ(state_, kPaused); |
75 ChangeState_Locked(kPlaying); | 75 ChangeState_Locked(kPlaying); |
76 callback.Run(); | 76 callback.Run(); |
77 earliest_end_time_ = now_cb_.Run(); | 77 earliest_end_time_ = now_cb_.Run(); |
78 | 78 |
79 if (algorithm_->playback_rate() != 0) | 79 if (algorithm_->playback_rate() != 0) |
80 DoPlay_Locked(); | 80 DoPlay_Locked(); |
81 else | 81 else |
82 DCHECK(!sink_playing_); | 82 DCHECK(!sink_playing_); |
83 } | 83 } |
84 | 84 |
85 void AudioRendererImpl::DoPlay_Locked() { | 85 void AudioRendererImpl::DoPlay_Locked() { |
86 DCHECK(message_loop_->BelongsToCurrentThread()); | 86 DCHECK(task_runner_->BelongsToCurrentThread()); |
87 lock_.AssertAcquired(); | 87 lock_.AssertAcquired(); |
88 earliest_end_time_ = now_cb_.Run(); | 88 earliest_end_time_ = now_cb_.Run(); |
89 | 89 |
90 if (state_ == kPlaying && !sink_playing_) { | 90 if (state_ == kPlaying && !sink_playing_) { |
91 { | 91 { |
92 base::AutoUnlock auto_unlock(lock_); | 92 base::AutoUnlock auto_unlock(lock_); |
93 sink_->Play(); | 93 sink_->Play(); |
94 } | 94 } |
95 | 95 |
96 sink_playing_ = true; | 96 sink_playing_ = true; |
97 } | 97 } |
98 } | 98 } |
99 | 99 |
100 void AudioRendererImpl::Pause(const base::Closure& callback) { | 100 void AudioRendererImpl::Pause(const base::Closure& callback) { |
101 DCHECK(message_loop_->BelongsToCurrentThread()); | 101 DCHECK(task_runner_->BelongsToCurrentThread()); |
102 | 102 |
103 base::AutoLock auto_lock(lock_); | 103 base::AutoLock auto_lock(lock_); |
104 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 104 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
105 state_ == kRebuffering) << "state_ == " << state_; | 105 state_ == kRebuffering) << "state_ == " << state_; |
106 pause_cb_ = callback; | 106 pause_cb_ = callback; |
107 ChangeState_Locked(kPaused); | 107 ChangeState_Locked(kPaused); |
108 | 108 |
109 // Pause only when we've completed our pending read. | 109 // Pause only when we've completed our pending read. |
110 if (!pending_read_) | 110 if (!pending_read_) |
111 base::ResetAndReturn(&pause_cb_).Run(); | 111 base::ResetAndReturn(&pause_cb_).Run(); |
112 | 112 |
113 DoPause_Locked(); | 113 DoPause_Locked(); |
114 } | 114 } |
115 | 115 |
116 void AudioRendererImpl::DoPause_Locked() { | 116 void AudioRendererImpl::DoPause_Locked() { |
117 DCHECK(message_loop_->BelongsToCurrentThread()); | 117 DCHECK(task_runner_->BelongsToCurrentThread()); |
118 lock_.AssertAcquired(); | 118 lock_.AssertAcquired(); |
119 | 119 |
120 if (sink_playing_) { | 120 if (sink_playing_) { |
121 { | 121 { |
122 base::AutoUnlock auto_unlock(lock_); | 122 base::AutoUnlock auto_unlock(lock_); |
123 sink_->Pause(); | 123 sink_->Pause(); |
124 } | 124 } |
125 sink_playing_ = false; | 125 sink_playing_ = false; |
126 } | 126 } |
127 } | 127 } |
128 | 128 |
129 void AudioRendererImpl::Flush(const base::Closure& callback) { | 129 void AudioRendererImpl::Flush(const base::Closure& callback) { |
130 DCHECK(message_loop_->BelongsToCurrentThread()); | 130 DCHECK(task_runner_->BelongsToCurrentThread()); |
131 | 131 |
132 if (decrypting_demuxer_stream_) { | 132 if (decrypting_demuxer_stream_) { |
133 decrypting_demuxer_stream_->Reset(base::Bind( | 133 decrypting_demuxer_stream_->Reset(base::Bind( |
134 &AudioRendererImpl::ResetDecoder, weak_this_, callback)); | 134 &AudioRendererImpl::ResetDecoder, weak_this_, callback)); |
135 return; | 135 return; |
136 } | 136 } |
137 | 137 |
138 decoder_->Reset(callback); | 138 decoder_->Reset(callback); |
139 } | 139 } |
140 | 140 |
141 void AudioRendererImpl::ResetDecoder(const base::Closure& callback) { | 141 void AudioRendererImpl::ResetDecoder(const base::Closure& callback) { |
142 DCHECK(message_loop_->BelongsToCurrentThread()); | 142 DCHECK(task_runner_->BelongsToCurrentThread()); |
143 decoder_->Reset(callback); | 143 decoder_->Reset(callback); |
144 } | 144 } |
145 | 145 |
146 void AudioRendererImpl::Stop(const base::Closure& callback) { | 146 void AudioRendererImpl::Stop(const base::Closure& callback) { |
147 DCHECK(message_loop_->BelongsToCurrentThread()); | 147 DCHECK(task_runner_->BelongsToCurrentThread()); |
148 DCHECK(!callback.is_null()); | 148 DCHECK(!callback.is_null()); |
149 | 149 |
150 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 150 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
151 // task-running guards that check |state_| with DCHECK(). | 151 // task-running guards that check |state_| with DCHECK(). |
152 | 152 |
153 if (sink_) { | 153 if (sink_) { |
154 sink_->Stop(); | 154 sink_->Stop(); |
155 sink_ = NULL; | 155 sink_ = NULL; |
156 } | 156 } |
157 | 157 |
158 { | 158 { |
159 base::AutoLock auto_lock(lock_); | 159 base::AutoLock auto_lock(lock_); |
160 ChangeState_Locked(kStopped); | 160 ChangeState_Locked(kStopped); |
161 algorithm_.reset(NULL); | 161 algorithm_.reset(NULL); |
162 init_cb_.Reset(); | 162 init_cb_.Reset(); |
163 underflow_cb_.Reset(); | 163 underflow_cb_.Reset(); |
164 time_cb_.Reset(); | 164 time_cb_.Reset(); |
165 } | 165 } |
166 | 166 |
167 callback.Run(); | 167 callback.Run(); |
168 } | 168 } |
169 | 169 |
170 void AudioRendererImpl::Preroll(base::TimeDelta time, | 170 void AudioRendererImpl::Preroll(base::TimeDelta time, |
171 const PipelineStatusCB& cb) { | 171 const PipelineStatusCB& cb) { |
172 DCHECK(message_loop_->BelongsToCurrentThread()); | 172 DCHECK(task_runner_->BelongsToCurrentThread()); |
173 | 173 |
174 base::AutoLock auto_lock(lock_); | 174 base::AutoLock auto_lock(lock_); |
175 DCHECK(!sink_playing_); | 175 DCHECK(!sink_playing_); |
176 DCHECK_EQ(state_, kPaused); | 176 DCHECK_EQ(state_, kPaused); |
177 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 177 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
178 DCHECK(pause_cb_.is_null()); | 178 DCHECK(pause_cb_.is_null()); |
179 DCHECK(preroll_cb_.is_null()); | 179 DCHECK(preroll_cb_.is_null()); |
180 | 180 |
181 ChangeState_Locked(kPrerolling); | 181 ChangeState_Locked(kPrerolling); |
182 preroll_cb_ = cb; | 182 preroll_cb_ = cb; |
(...skipping 14 matching lines...) Expand all Loading... |
197 } | 197 } |
198 | 198 |
199 void AudioRendererImpl::Initialize(DemuxerStream* stream, | 199 void AudioRendererImpl::Initialize(DemuxerStream* stream, |
200 const PipelineStatusCB& init_cb, | 200 const PipelineStatusCB& init_cb, |
201 const StatisticsCB& statistics_cb, | 201 const StatisticsCB& statistics_cb, |
202 const base::Closure& underflow_cb, | 202 const base::Closure& underflow_cb, |
203 const TimeCB& time_cb, | 203 const TimeCB& time_cb, |
204 const base::Closure& ended_cb, | 204 const base::Closure& ended_cb, |
205 const base::Closure& disabled_cb, | 205 const base::Closure& disabled_cb, |
206 const PipelineStatusCB& error_cb) { | 206 const PipelineStatusCB& error_cb) { |
207 DCHECK(message_loop_->BelongsToCurrentThread()); | 207 DCHECK(task_runner_->BelongsToCurrentThread()); |
208 DCHECK(stream); | 208 DCHECK(stream); |
209 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 209 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
210 DCHECK(!init_cb.is_null()); | 210 DCHECK(!init_cb.is_null()); |
211 DCHECK(!statistics_cb.is_null()); | 211 DCHECK(!statistics_cb.is_null()); |
212 DCHECK(!underflow_cb.is_null()); | 212 DCHECK(!underflow_cb.is_null()); |
213 DCHECK(!time_cb.is_null()); | 213 DCHECK(!time_cb.is_null()); |
214 DCHECK(!ended_cb.is_null()); | 214 DCHECK(!ended_cb.is_null()); |
215 DCHECK(!disabled_cb.is_null()); | 215 DCHECK(!disabled_cb.is_null()); |
216 DCHECK(!error_cb.is_null()); | 216 DCHECK(!error_cb.is_null()); |
217 DCHECK_EQ(kUninitialized, state_); | 217 DCHECK_EQ(kUninitialized, state_); |
(...skipping 10 matching lines...) Expand all Loading... |
228 | 228 |
229 decoder_selector_->SelectAudioDecoder( | 229 decoder_selector_->SelectAudioDecoder( |
230 stream, | 230 stream, |
231 statistics_cb, | 231 statistics_cb, |
232 base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_)); | 232 base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_)); |
233 } | 233 } |
234 | 234 |
235 void AudioRendererImpl::OnDecoderSelected( | 235 void AudioRendererImpl::OnDecoderSelected( |
236 scoped_ptr<AudioDecoder> decoder, | 236 scoped_ptr<AudioDecoder> decoder, |
237 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { | 237 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { |
238 DCHECK(message_loop_->BelongsToCurrentThread()); | 238 DCHECK(task_runner_->BelongsToCurrentThread()); |
239 | 239 |
240 base::AutoLock auto_lock(lock_); | 240 base::AutoLock auto_lock(lock_); |
241 scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass()); | 241 scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass()); |
242 | 242 |
243 if (state_ == kStopped) { | 243 if (state_ == kStopped) { |
244 DCHECK(!sink_); | 244 DCHECK(!sink_); |
245 return; | 245 return; |
246 } | 246 } |
247 | 247 |
248 if (!decoder) { | 248 if (!decoder) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 // Some sinks play on start... | 285 // Some sinks play on start... |
286 sink_->Pause(); | 286 sink_->Pause(); |
287 } | 287 } |
288 | 288 |
289 DCHECK(!sink_playing_); | 289 DCHECK(!sink_playing_); |
290 | 290 |
291 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 291 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
292 } | 292 } |
293 | 293 |
294 void AudioRendererImpl::ResumeAfterUnderflow() { | 294 void AudioRendererImpl::ResumeAfterUnderflow() { |
295 DCHECK(message_loop_->BelongsToCurrentThread()); | 295 DCHECK(task_runner_->BelongsToCurrentThread()); |
296 base::AutoLock auto_lock(lock_); | 296 base::AutoLock auto_lock(lock_); |
297 if (state_ == kUnderflow) { | 297 if (state_ == kUnderflow) { |
298 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 298 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
299 // shouldn't even reach the kUnderflow state to begin with. But for now | 299 // shouldn't even reach the kUnderflow state to begin with. But for now |
300 // we're just making sure that the audio buffer capacity (i.e. the | 300 // we're just making sure that the audio buffer capacity (i.e. the |
301 // number of bytes that need to be buffered for preroll to complete) | 301 // number of bytes that need to be buffered for preroll to complete) |
302 // does not increase due to an aborted preroll. | 302 // does not increase due to an aborted preroll. |
303 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) | 303 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) |
304 if (increase_preroll_on_underflow_ && !preroll_aborted_) | 304 if (increase_preroll_on_underflow_ && !preroll_aborted_) |
305 algorithm_->IncreaseQueueCapacity(); | 305 algorithm_->IncreaseQueueCapacity(); |
306 | 306 |
307 ChangeState_Locked(kRebuffering); | 307 ChangeState_Locked(kRebuffering); |
308 } | 308 } |
309 } | 309 } |
310 | 310 |
311 void AudioRendererImpl::SetVolume(float volume) { | 311 void AudioRendererImpl::SetVolume(float volume) { |
312 DCHECK(message_loop_->BelongsToCurrentThread()); | 312 DCHECK(task_runner_->BelongsToCurrentThread()); |
313 DCHECK(sink_); | 313 DCHECK(sink_); |
314 sink_->SetVolume(volume); | 314 sink_->SetVolume(volume); |
315 } | 315 } |
316 | 316 |
317 void AudioRendererImpl::DecodedAudioReady( | 317 void AudioRendererImpl::DecodedAudioReady( |
318 AudioDecoder::Status status, | 318 AudioDecoder::Status status, |
319 const scoped_refptr<AudioBuffer>& buffer) { | 319 const scoped_refptr<AudioBuffer>& buffer) { |
320 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | 320 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; |
321 DCHECK(message_loop_->BelongsToCurrentThread()); | 321 DCHECK(task_runner_->BelongsToCurrentThread()); |
322 | 322 |
323 base::AutoLock auto_lock(lock_); | 323 base::AutoLock auto_lock(lock_); |
324 DCHECK(state_ == kPaused || state_ == kPrerolling || state_ == kPlaying || | 324 DCHECK(state_ == kPaused || state_ == kPrerolling || state_ == kPlaying || |
325 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); | 325 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); |
326 | 326 |
327 CHECK(pending_read_); | 327 CHECK(pending_read_); |
328 pending_read_ = false; | 328 pending_read_ = false; |
329 | 329 |
330 if (status == AudioDecoder::kAborted) { | 330 if (status == AudioDecoder::kAborted) { |
331 HandleAbortedReadOrDecodeError(false); | 331 HandleAbortedReadOrDecodeError(false); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 } | 409 } |
410 return false; | 410 return false; |
411 } | 411 } |
412 | 412 |
413 void AudioRendererImpl::AttemptRead() { | 413 void AudioRendererImpl::AttemptRead() { |
414 base::AutoLock auto_lock(lock_); | 414 base::AutoLock auto_lock(lock_); |
415 AttemptRead_Locked(); | 415 AttemptRead_Locked(); |
416 } | 416 } |
417 | 417 |
418 void AudioRendererImpl::AttemptRead_Locked() { | 418 void AudioRendererImpl::AttemptRead_Locked() { |
419 DCHECK(message_loop_->BelongsToCurrentThread()); | 419 DCHECK(task_runner_->BelongsToCurrentThread()); |
420 lock_.AssertAcquired(); | 420 lock_.AssertAcquired(); |
421 | 421 |
422 if (!CanRead_Locked()) | 422 if (!CanRead_Locked()) |
423 return; | 423 return; |
424 | 424 |
425 pending_read_ = true; | 425 pending_read_ = true; |
426 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_)); | 426 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_)); |
427 } | 427 } |
428 | 428 |
429 bool AudioRendererImpl::CanRead_Locked() { | 429 bool AudioRendererImpl::CanRead_Locked() { |
(...skipping 11 matching lines...) Expand all Loading... |
441 case kRebuffering: | 441 case kRebuffering: |
442 break; | 442 break; |
443 } | 443 } |
444 | 444 |
445 return !pending_read_ && !received_end_of_stream_ && | 445 return !pending_read_ && !received_end_of_stream_ && |
446 !algorithm_->IsQueueFull(); | 446 !algorithm_->IsQueueFull(); |
447 } | 447 } |
448 | 448 |
449 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 449 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
450 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 450 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
451 DCHECK(message_loop_->BelongsToCurrentThread()); | 451 DCHECK(task_runner_->BelongsToCurrentThread()); |
452 DCHECK_GE(playback_rate, 0); | 452 DCHECK_GE(playback_rate, 0); |
453 DCHECK(sink_); | 453 DCHECK(sink_); |
454 | 454 |
455 base::AutoLock auto_lock(lock_); | 455 base::AutoLock auto_lock(lock_); |
456 | 456 |
457 // We have two cases here: | 457 // We have two cases here: |
458 // Play: current_playback_rate == 0 && playback_rate != 0 | 458 // Play: current_playback_rate == 0 && playback_rate != 0 |
459 // Pause: current_playback_rate != 0 && playback_rate == 0 | 459 // Pause: current_playback_rate != 0 && playback_rate == 0 |
460 float current_playback_rate = algorithm_->playback_rate(); | 460 float current_playback_rate = algorithm_->playback_rate(); |
461 if (current_playback_rate == 0 && playback_rate != 0) | 461 if (current_playback_rate == 0 && playback_rate != 0) |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 ChangeState_Locked(kUnderflow); | 526 ChangeState_Locked(kUnderflow); |
527 underflow_cb = underflow_cb_; | 527 underflow_cb = underflow_cb_; |
528 } else { | 528 } else { |
529 // We can't write any data this cycle. For example, we may have | 529 // We can't write any data this cycle. For example, we may have |
530 // sent all available data to the audio device while not reaching | 530 // sent all available data to the audio device while not reaching |
531 // |earliest_end_time_|. | 531 // |earliest_end_time_|. |
532 } | 532 } |
533 } | 533 } |
534 | 534 |
535 if (CanRead_Locked()) { | 535 if (CanRead_Locked()) { |
536 message_loop_->PostTask(FROM_HERE, base::Bind( | 536 task_runner_->PostTask(FROM_HERE, base::Bind( |
537 &AudioRendererImpl::AttemptRead, weak_this_)); | 537 &AudioRendererImpl::AttemptRead, weak_this_)); |
538 } | 538 } |
539 | 539 |
540 // The |audio_time_buffered_| is the ending timestamp of the last frame | 540 // The |audio_time_buffered_| is the ending timestamp of the last frame |
541 // buffered at the audio device. |playback_delay| is the amount of time | 541 // buffered at the audio device. |playback_delay| is the amount of time |
542 // buffered at the audio device. The current time can be computed by their | 542 // buffered at the audio device. The current time can be computed by their |
543 // difference. | 543 // difference. |
544 if (audio_time_buffered_ != kNoTimestamp()) { | 544 if (audio_time_buffered_ != kNoTimestamp()) { |
545 // Adjust the delay according to playback rate. | 545 // Adjust the delay according to playback rate. |
546 base::TimeDelta adjusted_playback_delay = | 546 base::TimeDelta adjusted_playback_delay = |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 } | 640 } |
641 } | 641 } |
642 | 642 |
643 void AudioRendererImpl::ChangeState_Locked(State new_state) { | 643 void AudioRendererImpl::ChangeState_Locked(State new_state) { |
644 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; | 644 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; |
645 lock_.AssertAcquired(); | 645 lock_.AssertAcquired(); |
646 state_ = new_state; | 646 state_ = new_state; |
647 } | 647 } |
648 | 648 |
649 } // namespace media | 649 } // namespace media |
OLD | NEW |