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 "media/audio/audio_util.h" | 15 #include "media/audio/audio_util.h" |
16 #include "media/base/demuxer_stream.h" | 16 #include "media/base/demuxer_stream.h" |
17 | 17 |
18 namespace media { | 18 namespace media { |
19 | 19 |
20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
21 : state_(kUninitialized), | 21 : state_(kUninitialized), |
22 pending_read_(false), | 22 pending_read_(false), |
23 received_end_of_stream_(false), | 23 received_end_of_stream_(false), |
24 rendered_end_of_stream_(false), | 24 rendered_end_of_stream_(false), |
25 audio_time_buffered_(kNoTimestamp()), | 25 audio_time_buffered_(kNoTimestamp()), |
26 current_time_(kNoTimestamp()), | 26 current_time_(kNoTimestamp()), |
27 bytes_per_frame_(0), | 27 bytes_per_frame_(0), |
28 bytes_per_second_(0), | |
29 stopped_(false), | 28 stopped_(false), |
30 sink_(sink), | 29 sink_(sink), |
31 is_initialized_(false), | |
32 underflow_disabled_(false), | 30 underflow_disabled_(false), |
33 preroll_aborted_(false) { | 31 preroll_aborted_(false) { |
34 } | 32 } |
35 | 33 |
36 void AudioRendererImpl::Play(const base::Closure& callback) { | 34 void AudioRendererImpl::Play(const base::Closure& callback) { |
37 { | 35 { |
38 base::AutoLock auto_lock(lock_); | 36 base::AutoLock auto_lock(lock_); |
39 DCHECK_EQ(kPaused, state_); | 37 DCHECK_EQ(kPaused, state_); |
40 state_ = kPlaying; | 38 state_ = kPlaying; |
41 callback.Run(); | 39 callback.Run(); |
42 } | 40 } |
43 | 41 |
44 if (stopped_) | 42 if (stopped_) |
45 return; | 43 return; |
46 | 44 |
47 if (GetPlaybackRate() != 0.0f) { | 45 if (GetPlaybackRate() != 0.0f) { |
48 DoPlay(); | 46 DoPlay(); |
49 } else { | 47 } else { |
50 DoPause(); | 48 DoPause(); |
51 } | 49 } |
52 } | 50 } |
53 | 51 |
54 void AudioRendererImpl::DoPlay() { | 52 void AudioRendererImpl::DoPlay() { |
55 earliest_end_time_ = base::Time::Now(); | 53 earliest_end_time_ = base::Time::Now(); |
56 DCHECK(sink_.get()); | |
57 sink_->Play(); | 54 sink_->Play(); |
58 } | 55 } |
59 | 56 |
60 void AudioRendererImpl::Pause(const base::Closure& callback) { | 57 void AudioRendererImpl::Pause(const base::Closure& callback) { |
61 { | 58 { |
62 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
63 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 60 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
64 state_ == kRebuffering); | 61 state_ == kRebuffering); |
65 pause_cb_ = callback; | 62 pause_cb_ = callback; |
66 state_ = kPaused; | 63 state_ = kPaused; |
67 | 64 |
68 // Pause only when we've completed our pending read. | 65 // Pause only when we've completed our pending read. |
69 if (!pending_read_) | 66 if (!pending_read_) |
70 base::ResetAndReturn(&pause_cb_).Run(); | 67 base::ResetAndReturn(&pause_cb_).Run(); |
71 } | 68 } |
72 | 69 |
73 if (stopped_) | 70 if (stopped_) |
74 return; | 71 return; |
75 | 72 |
76 DoPause(); | 73 DoPause(); |
77 } | 74 } |
78 | 75 |
79 void AudioRendererImpl::DoPause() { | 76 void AudioRendererImpl::DoPause() { |
80 DCHECK(sink_.get()); | |
81 sink_->Pause(false); | 77 sink_->Pause(false); |
82 } | 78 } |
83 | 79 |
84 void AudioRendererImpl::Flush(const base::Closure& callback) { | 80 void AudioRendererImpl::Flush(const base::Closure& callback) { |
85 decoder_->Reset(callback); | 81 decoder_->Reset(callback); |
86 } | 82 } |
87 | 83 |
88 void AudioRendererImpl::Stop(const base::Closure& callback) { | 84 void AudioRendererImpl::Stop(const base::Closure& callback) { |
89 DCHECK(!callback.is_null()); | 85 DCHECK(!callback.is_null()); |
90 | 86 |
91 if (!stopped_) { | 87 if (!stopped_) { |
92 DCHECK(sink_.get()); | |
93 sink_->Stop(); | 88 sink_->Stop(); |
94 | |
95 stopped_ = true; | 89 stopped_ = true; |
96 } | 90 } |
97 { | 91 { |
98 base::AutoLock auto_lock(lock_); | 92 base::AutoLock auto_lock(lock_); |
99 state_ = kStopped; | 93 state_ = kStopped; |
100 algorithm_.reset(NULL); | 94 algorithm_.reset(NULL); |
101 init_cb_.Reset(); | 95 init_cb_.Reset(); |
102 underflow_cb_.Reset(); | 96 underflow_cb_.Reset(); |
103 time_cb_.Reset(); | 97 time_cb_.Reset(); |
104 } | 98 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 const base::Closure& underflow_cb, | 136 const base::Closure& underflow_cb, |
143 const TimeCB& time_cb, | 137 const TimeCB& time_cb, |
144 const base::Closure& ended_cb, | 138 const base::Closure& ended_cb, |
145 const base::Closure& disabled_cb, | 139 const base::Closure& disabled_cb, |
146 const PipelineStatusCB& error_cb) { | 140 const PipelineStatusCB& error_cb) { |
147 base::AutoLock auto_lock(lock_); | 141 base::AutoLock auto_lock(lock_); |
148 DCHECK(stream); | 142 DCHECK(stream); |
149 DCHECK(!decoders.empty()); | 143 DCHECK(!decoders.empty()); |
150 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 144 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
151 DCHECK(!init_cb.is_null()); | 145 DCHECK(!init_cb.is_null()); |
| 146 DCHECK(!statistics_cb.is_null()); |
152 DCHECK(!underflow_cb.is_null()); | 147 DCHECK(!underflow_cb.is_null()); |
153 DCHECK(!time_cb.is_null()); | 148 DCHECK(!time_cb.is_null()); |
154 DCHECK(!ended_cb.is_null()); | 149 DCHECK(!ended_cb.is_null()); |
155 DCHECK(!disabled_cb.is_null()); | 150 DCHECK(!disabled_cb.is_null()); |
156 DCHECK(!error_cb.is_null()); | 151 DCHECK(!error_cb.is_null()); |
157 DCHECK_EQ(kUninitialized, state_); | 152 DCHECK_EQ(kUninitialized, state_); |
158 | 153 |
159 init_cb_ = init_cb; | 154 init_cb_ = init_cb; |
160 statistics_cb_ = statistics_cb; | 155 statistics_cb_ = statistics_cb; |
161 underflow_cb_ = underflow_cb; | 156 underflow_cb_ = underflow_cb; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | 196 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { |
202 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | 197 InitializeNextDecoder(demuxer_stream, decoders.Pass()); |
203 return; | 198 return; |
204 } | 199 } |
205 | 200 |
206 if (status != PIPELINE_OK) { | 201 if (status != PIPELINE_OK) { |
207 base::ResetAndReturn(&init_cb_).Run(status); | 202 base::ResetAndReturn(&init_cb_).Run(status); |
208 return; | 203 return; |
209 } | 204 } |
210 | 205 |
211 // Create a callback so our algorithm can request more reads. | 206 // We're all good! Continue initializing the rest of the audio renderer based |
212 base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); | 207 // on the decoder format. |
213 | 208 |
214 // Construct the algorithm. | |
215 algorithm_.reset(new AudioRendererAlgorithm()); | |
216 | |
217 // Initialize our algorithm with media properties, initial playback rate, | |
218 // and a callback to request more reads from the data source. | |
219 ChannelLayout channel_layout = decoder_->channel_layout(); | 209 ChannelLayout channel_layout = decoder_->channel_layout(); |
220 int channels = ChannelLayoutToChannelCount(channel_layout); | 210 int channels = ChannelLayoutToChannelCount(channel_layout); |
221 int bits_per_channel = decoder_->bits_per_channel(); | 211 int bits_per_channel = decoder_->bits_per_channel(); |
222 int sample_rate = decoder_->samples_per_second(); | 212 int sample_rate = decoder_->samples_per_second(); |
223 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. | 213 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. |
224 bytes_per_frame_ = channels * bits_per_channel / 8; | 214 bytes_per_frame_ = channels * bits_per_channel / 8; |
225 | 215 |
226 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, | 216 algorithm_.reset(new AudioRendererAlgorithm()); |
227 bits_per_channel); | 217 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { |
228 if (!config_ok || is_initialized_) { | |
229 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 218 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
230 return; | 219 return; |
231 } | 220 } |
232 | 221 |
233 if (config_ok) | 222 algorithm_->Initialize( |
234 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); | 223 channels, sample_rate, bits_per_channel, 0.0f, |
| 224 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); |
235 | 225 |
236 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 226 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
237 // does not currently support all the sample-rates that we require. | 227 // does not currently support all the sample-rates that we require. |
238 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 228 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
239 // for more details. | 229 // for more details. |
240 audio_parameters_ = AudioParameters( | 230 audio_parameters_ = AudioParameters( |
241 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, | 231 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, |
242 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); | 232 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); |
243 | 233 |
244 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); | 234 sink_->Initialize(audio_parameters_, this); |
| 235 sink_->Start(); |
245 | 236 |
246 DCHECK(sink_.get()); | |
247 DCHECK(!is_initialized_); | |
248 | |
249 sink_->Initialize(audio_parameters_, this); | |
250 | |
251 sink_->Start(); | |
252 is_initialized_ = true; | |
253 | |
254 // Finally, execute the start callback. | |
255 state_ = kPaused; | 237 state_ = kPaused; |
256 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 238 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
257 } | 239 } |
258 | 240 |
259 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 241 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
260 base::AutoLock auto_lock(lock_); | 242 base::AutoLock auto_lock(lock_); |
261 if (state_ == kUnderflow) { | 243 if (state_ == kUnderflow) { |
262 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 244 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
263 // shouldn't even reach the kUnderflow state to begin with. But for now | 245 // shouldn't even reach the kUnderflow state to begin with. But for now |
264 // we're just making sure that the audio buffer capacity (i.e. the | 246 // we're just making sure that the audio buffer capacity (i.e. the |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 520 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
539 playback_rate))); | 521 playback_rate))); |
540 } | 522 } |
541 earliest_end_time_ = | 523 earliest_end_time_ = |
542 std::max(earliest_end_time_, | 524 std::max(earliest_end_time_, |
543 time_now + request_delay + predicted_play_time); | 525 time_now + request_delay + predicted_play_time); |
544 } | 526 } |
545 } | 527 } |
546 | 528 |
547 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 529 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
548 if (bytes_per_second_) { | 530 int bytes_per_second = audio_parameters_.GetBytesPerSecond(); |
549 return base::TimeDelta::FromMicroseconds( | 531 CHECK(bytes_per_second); |
550 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 532 return base::TimeDelta::FromMicroseconds( |
551 } | 533 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second); |
552 return base::TimeDelta(); | |
553 } | 534 } |
554 | 535 |
555 void AudioRendererImpl::OnRenderError() { | 536 void AudioRendererImpl::OnRenderError() { |
556 disabled_cb_.Run(); | 537 disabled_cb_.Run(); |
557 } | 538 } |
558 | 539 |
559 void AudioRendererImpl::DisableUnderflowForTesting() { | 540 void AudioRendererImpl::DisableUnderflowForTesting() { |
560 DCHECK(!is_initialized_); | |
561 underflow_disabled_ = true; | 541 underflow_disabled_ = true; |
562 } | 542 } |
563 | 543 |
564 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { | 544 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
565 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; | 545 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; |
566 switch (state_) { | 546 switch (state_) { |
567 case kUninitialized: | 547 case kUninitialized: |
568 NOTREACHED(); | 548 NOTREACHED(); |
569 return; | 549 return; |
570 case kPaused: | 550 case kPaused: |
(...skipping 11 matching lines...) Expand all Loading... |
582 case kUnderflow: | 562 case kUnderflow: |
583 case kRebuffering: | 563 case kRebuffering: |
584 case kStopped: | 564 case kStopped: |
585 if (status != PIPELINE_OK) | 565 if (status != PIPELINE_OK) |
586 error_cb_.Run(status); | 566 error_cb_.Run(status); |
587 return; | 567 return; |
588 } | 568 } |
589 } | 569 } |
590 | 570 |
591 } // namespace media | 571 } // namespace media |
OLD | NEW |