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 "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "media/audio/audio_util.h" | 13 #include "media/audio/audio_util.h" |
14 #include "media/base/demuxer_stream.h" | |
14 | 15 |
15 namespace media { | 16 namespace media { |
16 | 17 |
17 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | 18 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) |
18 : state_(kUninitialized), | 19 : state_(kUninitialized), |
19 pending_read_(false), | 20 pending_read_(false), |
20 received_end_of_stream_(false), | 21 received_end_of_stream_(false), |
21 rendered_end_of_stream_(false), | 22 rendered_end_of_stream_(false), |
22 audio_time_buffered_(kNoTimestamp()), | 23 audio_time_buffered_(kNoTimestamp()), |
23 current_time_(kNoTimestamp()), | 24 current_time_(kNoTimestamp()), |
24 bytes_per_frame_(0), | 25 bytes_per_frame_(0), |
25 bytes_per_second_(0), | |
26 stopped_(false), | 26 stopped_(false), |
27 sink_(sink), | 27 sink_(sink), |
28 is_initialized_(false), | |
29 underflow_disabled_(false) { | 28 underflow_disabled_(false) { |
30 } | 29 } |
31 | 30 |
32 void AudioRendererImpl::Play(const base::Closure& callback) { | 31 void AudioRendererImpl::Play(const base::Closure& callback) { |
33 { | 32 { |
34 base::AutoLock auto_lock(lock_); | 33 base::AutoLock auto_lock(lock_); |
35 DCHECK_EQ(kPaused, state_); | 34 DCHECK_EQ(kPaused, state_); |
36 state_ = kPlaying; | 35 state_ = kPlaying; |
37 callback.Run(); | 36 callback.Run(); |
38 } | 37 } |
39 | 38 |
40 if (stopped_) | 39 if (stopped_) |
41 return; | 40 return; |
42 | 41 |
43 if (GetPlaybackRate() != 0.0f) { | 42 if (GetPlaybackRate() != 0.0f) { |
44 DoPlay(); | 43 DoPlay(); |
45 } else { | 44 } else { |
46 DoPause(); | 45 DoPause(); |
47 } | 46 } |
48 } | 47 } |
49 | 48 |
50 void AudioRendererImpl::DoPlay() { | 49 void AudioRendererImpl::DoPlay() { |
51 earliest_end_time_ = base::Time::Now(); | 50 earliest_end_time_ = base::Time::Now(); |
52 DCHECK(sink_.get()); | |
Ami GONE FROM CHROMIUM
2012/09/07 14:40:02
this is just random cleanup?
| |
53 sink_->Play(); | 51 sink_->Play(); |
54 } | 52 } |
55 | 53 |
56 void AudioRendererImpl::Pause(const base::Closure& callback) { | 54 void AudioRendererImpl::Pause(const base::Closure& callback) { |
57 { | 55 { |
58 base::AutoLock auto_lock(lock_); | 56 base::AutoLock auto_lock(lock_); |
59 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 57 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
60 state_ == kRebuffering); | 58 state_ == kRebuffering); |
61 pause_cb_ = callback; | 59 pause_cb_ = callback; |
62 state_ = kPaused; | 60 state_ = kPaused; |
63 | 61 |
64 // Pause only when we've completed our pending read. | 62 // Pause only when we've completed our pending read. |
65 if (!pending_read_) | 63 if (!pending_read_) |
66 base::ResetAndReturn(&pause_cb_).Run(); | 64 base::ResetAndReturn(&pause_cb_).Run(); |
67 } | 65 } |
68 | 66 |
69 if (stopped_) | 67 if (stopped_) |
70 return; | 68 return; |
71 | 69 |
72 DoPause(); | 70 DoPause(); |
73 } | 71 } |
74 | 72 |
75 void AudioRendererImpl::DoPause() { | 73 void AudioRendererImpl::DoPause() { |
76 DCHECK(sink_.get()); | |
77 sink_->Pause(false); | 74 sink_->Pause(false); |
78 } | 75 } |
79 | 76 |
80 void AudioRendererImpl::Flush(const base::Closure& callback) { | 77 void AudioRendererImpl::Flush(const base::Closure& callback) { |
81 decoder_->Reset(callback); | 78 decoder_->Reset(callback); |
82 } | 79 } |
83 | 80 |
84 void AudioRendererImpl::Stop(const base::Closure& callback) { | 81 void AudioRendererImpl::Stop(const base::Closure& callback) { |
85 if (!stopped_) { | 82 if (!stopped_) { |
86 DCHECK(sink_.get()); | |
87 sink_->Stop(); | 83 sink_->Stop(); |
88 | |
89 stopped_ = true; | 84 stopped_ = true; |
90 } | 85 } |
91 { | 86 { |
92 base::AutoLock auto_lock(lock_); | 87 base::AutoLock auto_lock(lock_); |
93 state_ = kStopped; | 88 state_ = kStopped; |
94 algorithm_.reset(NULL); | 89 algorithm_.reset(NULL); |
95 time_cb_.Reset(); | 90 time_cb_.Reset(); |
96 underflow_cb_.Reset(); | 91 underflow_cb_.Reset(); |
97 } | 92 } |
98 if (!callback.is_null()) { | 93 if (!callback.is_null()) { |
(...skipping 22 matching lines...) Expand all Loading... | |
121 algorithm_->FlushBuffers(); | 116 algorithm_->FlushBuffers(); |
122 | 117 |
123 if (stopped_) | 118 if (stopped_) |
124 return; | 119 return; |
125 | 120 |
126 // Pause and flush the stream when we preroll to a new location. | 121 // Pause and flush the stream when we preroll to a new location. |
127 earliest_end_time_ = base::Time::Now(); | 122 earliest_end_time_ = base::Time::Now(); |
128 sink_->Pause(true); | 123 sink_->Pause(true); |
129 } | 124 } |
130 | 125 |
131 void AudioRendererImpl::Initialize(const scoped_refptr<AudioDecoder>& decoder, | 126 void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream, |
127 const AudioDecoderList& decoders, | |
132 const PipelineStatusCB& init_cb, | 128 const PipelineStatusCB& init_cb, |
129 const StatisticsCB& statistics_cb, | |
133 const base::Closure& underflow_cb, | 130 const base::Closure& underflow_cb, |
134 const TimeCB& time_cb, | 131 const TimeCB& time_cb, |
135 const base::Closure& ended_cb, | 132 const base::Closure& ended_cb, |
136 const base::Closure& disabled_cb, | 133 const base::Closure& disabled_cb, |
137 const PipelineStatusCB& error_cb) { | 134 const PipelineStatusCB& error_cb) { |
138 DCHECK(decoder); | 135 base::AutoLock l(lock_); |
Ami GONE FROM CHROMIUM
2012/09/07 14:40:02
"l" is not stylish
| |
136 DCHECK(stream); | |
137 DCHECK(!decoders.empty()); | |
138 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | |
139 DCHECK(!init_cb.is_null()); | 139 DCHECK(!init_cb.is_null()); |
140 DCHECK(!statistics_cb.is_null()); | |
140 DCHECK(!underflow_cb.is_null()); | 141 DCHECK(!underflow_cb.is_null()); |
141 DCHECK(!time_cb.is_null()); | 142 DCHECK(!time_cb.is_null()); |
142 DCHECK(!ended_cb.is_null()); | 143 DCHECK(!ended_cb.is_null()); |
143 DCHECK(!disabled_cb.is_null()); | 144 DCHECK(!disabled_cb.is_null()); |
144 DCHECK(!error_cb.is_null()); | 145 DCHECK(!error_cb.is_null()); |
145 DCHECK_EQ(kUninitialized, state_); | 146 DCHECK_EQ(kUninitialized, state_); |
146 decoder_ = decoder; | 147 init_cb_ = init_cb; |
148 statistics_cb_ = statistics_cb; | |
Ami GONE FROM CHROMIUM
2012/09/07 14:40:02
This is only used during the init dance, right?
Wh
| |
147 underflow_cb_ = underflow_cb; | 149 underflow_cb_ = underflow_cb; |
148 time_cb_ = time_cb; | 150 time_cb_ = time_cb; |
149 ended_cb_ = ended_cb; | 151 ended_cb_ = ended_cb; |
150 disabled_cb_ = disabled_cb; | 152 disabled_cb_ = disabled_cb; |
151 error_cb_ = error_cb; | 153 error_cb_ = error_cb; |
152 | 154 |
153 // Create a callback so our algorithm can request more reads. | 155 scoped_ptr<AudioDecoderList> decoder_list(new AudioDecoderList(decoders)); |
154 base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); | 156 InitializeNextDecoder(stream, decoder_list.Pass()); |
157 } | |
155 | 158 |
156 // Construct the algorithm. | 159 void AudioRendererImpl::InitializeNextDecoder( |
157 algorithm_.reset(new AudioRendererAlgorithm()); | 160 const scoped_refptr<DemuxerStream>& demuxer_stream, |
161 scoped_ptr<AudioDecoderList> decoders) { | |
162 lock_.AssertAcquired(); | |
Ami GONE FROM CHROMIUM
2012/09/07 14:40:02
this locking is making me very sad.
If you dropped
| |
163 DCHECK(!decoders->empty()); | |
158 | 164 |
159 // Initialize our algorithm with media properties, initial playback rate, | 165 scoped_refptr<AudioDecoder> decoder = decoders->front(); |
Ami GONE FROM CHROMIUM
2012/09/07 14:40:02
put it straight into decoder_ instead?
| |
160 // and a callback to request more reads from the data source. | 166 decoders->pop_front(); |
167 | |
168 DCHECK(decoder); | |
169 decoder_ = decoder; | |
170 | |
171 base::AutoUnlock auto_unlock(lock_); | |
172 decoder->Initialize( | |
173 demuxer_stream, | |
174 base::Bind(&AudioRendererImpl::OnDecoderInitDone, this, | |
175 demuxer_stream, | |
176 base::Passed(&decoders)), | |
177 statistics_cb_); | |
178 } | |
179 | |
180 void AudioRendererImpl::OnDecoderInitDone( | |
181 const scoped_refptr<DemuxerStream>& demuxer_stream, | |
182 scoped_ptr<AudioDecoderList> decoders, | |
183 PipelineStatus status) { | |
184 base::AutoLock auto_lock(lock_); | |
185 | |
186 if (stopped_ || state_ == kStopped) | |
187 return; | |
188 | |
189 if (!decoders->empty() && status == DECODER_ERROR_NOT_SUPPORTED) { | |
190 InitializeNextDecoder(demuxer_stream, decoders.Pass()); | |
191 return; | |
192 } | |
193 | |
194 if (status != PIPELINE_OK) { | |
195 base::ResetAndReturn(&init_cb_).Run(status); | |
196 return; | |
197 } | |
198 | |
199 // We're all good! Continue initializing the rest of the audio renderer based | |
200 // on the decoder format. | |
201 | |
161 ChannelLayout channel_layout = decoder_->channel_layout(); | 202 ChannelLayout channel_layout = decoder_->channel_layout(); |
162 int channels = ChannelLayoutToChannelCount(channel_layout); | 203 int channels = ChannelLayoutToChannelCount(channel_layout); |
163 int bits_per_channel = decoder_->bits_per_channel(); | 204 int bits_per_channel = decoder_->bits_per_channel(); |
164 int sample_rate = decoder_->samples_per_second(); | 205 int sample_rate = decoder_->samples_per_second(); |
165 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. | 206 // TODO(vrk): Add method to AudioDecoder to compute bytes per frame. |
166 bytes_per_frame_ = channels * bits_per_channel / 8; | 207 bytes_per_frame_ = channels * bits_per_channel / 8; |
167 | 208 |
168 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, | 209 algorithm_.reset(new AudioRendererAlgorithm()); |
scherkus (not reviewing)
2012/09/07 13:59:54
this was some miscellaneous cleanup
| |
169 bits_per_channel); | 210 if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) { |
170 if (!config_ok || is_initialized_) { | 211 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
171 init_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
172 return; | 212 return; |
173 } | 213 } |
174 | 214 |
175 if (config_ok) | 215 algorithm_->Initialize( |
176 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); | 216 channels, sample_rate, bits_per_channel, 0.0f, |
217 base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this)); | |
177 | 218 |
178 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | 219 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY |
179 // does not currently support all the sample-rates that we require. | 220 // does not currently support all the sample-rates that we require. |
180 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | 221 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 |
181 // for more details. | 222 // for more details. |
182 audio_parameters_ = AudioParameters( | 223 audio_parameters_ = AudioParameters( |
183 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, | 224 AudioParameters::AUDIO_PCM_LINEAR, channel_layout, sample_rate, |
184 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); | 225 bits_per_channel, GetHighLatencyOutputBufferSize(sample_rate)); |
185 | 226 |
186 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); | 227 sink_->Initialize(audio_parameters_, this); |
228 sink_->Start(); | |
187 | 229 |
188 DCHECK(sink_.get()); | |
189 DCHECK(!is_initialized_); | |
190 | |
191 sink_->Initialize(audio_parameters_, this); | |
192 | |
193 sink_->Start(); | |
194 is_initialized_ = true; | |
195 | |
196 // Finally, execute the start callback. | |
197 state_ = kPaused; | 230 state_ = kPaused; |
198 init_cb.Run(PIPELINE_OK); | 231 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
199 } | 232 } |
200 | 233 |
201 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 234 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
202 base::AutoLock auto_lock(lock_); | 235 base::AutoLock auto_lock(lock_); |
203 if (state_ == kUnderflow) { | 236 if (state_ == kUnderflow) { |
204 if (buffer_more_audio) | 237 if (buffer_more_audio) |
205 algorithm_->IncreaseQueueCapacity(); | 238 algorithm_->IncreaseQueueCapacity(); |
206 | 239 |
207 state_ = kRebuffering; | 240 state_ = kRebuffering; |
208 } | 241 } |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
474 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | 507 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * |
475 playback_rate))); | 508 playback_rate))); |
476 } | 509 } |
477 earliest_end_time_ = | 510 earliest_end_time_ = |
478 std::max(earliest_end_time_, | 511 std::max(earliest_end_time_, |
479 time_now + request_delay + predicted_play_time); | 512 time_now + request_delay + predicted_play_time); |
480 } | 513 } |
481 } | 514 } |
482 | 515 |
483 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 516 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
484 if (bytes_per_second_) { | 517 int bytes_per_second = audio_parameters_.GetBytesPerSecond(); |
485 return base::TimeDelta::FromMicroseconds( | 518 CHECK(bytes_per_second); |
scherkus (not reviewing)
2012/09/07 13:59:54
calling algorithm_->ValidateConfig() should preven
| |
486 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 519 return base::TimeDelta::FromMicroseconds( |
487 } | 520 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second); |
488 return base::TimeDelta(); | |
489 } | 521 } |
490 | 522 |
491 void AudioRendererImpl::OnRenderError() { | 523 void AudioRendererImpl::OnRenderError() { |
492 disabled_cb_.Run(); | 524 disabled_cb_.Run(); |
493 } | 525 } |
494 | 526 |
495 void AudioRendererImpl::DisableUnderflowForTesting() { | 527 void AudioRendererImpl::DisableUnderflowForTesting() { |
496 DCHECK(!is_initialized_); | |
497 underflow_disabled_ = true; | 528 underflow_disabled_ = true; |
498 } | 529 } |
499 | 530 |
500 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { | 531 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
501 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; | 532 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; |
502 switch (state_) { | 533 switch (state_) { |
503 case kUninitialized: | 534 case kUninitialized: |
504 NOTREACHED(); | 535 NOTREACHED(); |
505 return; | 536 return; |
506 case kPaused: | 537 case kPaused: |
507 if (status != PIPELINE_OK) | 538 if (status != PIPELINE_OK) |
508 error_cb_.Run(status); | 539 error_cb_.Run(status); |
509 base::ResetAndReturn(&pause_cb_).Run(); | 540 base::ResetAndReturn(&pause_cb_).Run(); |
510 return; | 541 return; |
511 case kPrerolling: | 542 case kPrerolling: |
512 state_ = kPaused; | 543 state_ = kPaused; |
513 base::ResetAndReturn(&preroll_cb_).Run(status); | 544 base::ResetAndReturn(&preroll_cb_).Run(status); |
514 return; | 545 return; |
515 case kPlaying: | 546 case kPlaying: |
516 case kUnderflow: | 547 case kUnderflow: |
517 case kRebuffering: | 548 case kRebuffering: |
518 case kStopped: | 549 case kStopped: |
519 if (status != PIPELINE_OK) | 550 if (status != PIPELINE_OK) |
520 error_cb_.Run(status); | 551 error_cb_.Run(status); |
521 return; | 552 return; |
522 } | 553 } |
523 } | 554 } |
524 | 555 |
525 } // namespace media | 556 } // namespace media |
OLD | NEW |