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

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

Issue 10918022: Move AudioDecoder initialization into AudioRenderer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 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 "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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698