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

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

Issue 9395057: Fix muted audio when playback rate != 1.0 or 0.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 10 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_base.h" 5 #include "media/filters/audio_renderer_base.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "media/base/filter_host.h" 13 #include "media/base/filter_host.h"
14 14
15 namespace media { 15 namespace media {
16 16
17 AudioRendererBase::AudioRendererBase() 17 AudioRendererBase::AudioRendererBase()
18 : state_(kUninitialized), 18 : state_(kUninitialized),
19 pending_read_(false), 19 pending_read_(false),
20 recieved_end_of_stream_(false), 20 received_end_of_stream_(false),
21 rendered_end_of_stream_(false), 21 rendered_end_of_stream_(false),
22 bytes_per_frame_(0),
22 read_cb_(base::Bind(&AudioRendererBase::DecodedAudioReady, 23 read_cb_(base::Bind(&AudioRendererBase::DecodedAudioReady,
23 base::Unretained(this))) { 24 base::Unretained(this))) {
24 } 25 }
25 26
26 AudioRendererBase::~AudioRendererBase() { 27 AudioRendererBase::~AudioRendererBase() {
27 // Stop() should have been called and |algorithm_| should have been destroyed. 28 // Stop() should have been called and |algorithm_| should have been destroyed.
28 DCHECK(state_ == kUninitialized || state_ == kStopped); 29 DCHECK(state_ == kUninitialized || state_ == kStopped);
29 DCHECK(!algorithm_.get()); 30 DCHECK(!algorithm_.get());
30 } 31 }
31 32
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 DCHECK_EQ(kPaused, state_); 75 DCHECK_EQ(kPaused, state_);
75 DCHECK(!pending_read_) << "Pending read must complete before seeking"; 76 DCHECK(!pending_read_) << "Pending read must complete before seeking";
76 DCHECK(pause_callback_.is_null()); 77 DCHECK(pause_callback_.is_null());
77 DCHECK(seek_cb_.is_null()); 78 DCHECK(seek_cb_.is_null());
78 state_ = kSeeking; 79 state_ = kSeeking;
79 seek_cb_ = cb; 80 seek_cb_ = cb;
80 seek_timestamp_ = time; 81 seek_timestamp_ = time;
81 82
82 // Throw away everything and schedule our reads. 83 // Throw away everything and schedule our reads.
83 last_fill_buffer_time_ = base::TimeDelta(); 84 last_fill_buffer_time_ = base::TimeDelta();
84 recieved_end_of_stream_ = false; 85 received_end_of_stream_ = false;
85 rendered_end_of_stream_ = false; 86 rendered_end_of_stream_ = false;
86 87
87 // |algorithm_| will request more reads. 88 // |algorithm_| will request more reads.
88 algorithm_->FlushBuffers(); 89 algorithm_->FlushBuffers();
89 } 90 }
90 91
91 void AudioRendererBase::Initialize(const scoped_refptr<AudioDecoder>& decoder, 92 void AudioRendererBase::Initialize(const scoped_refptr<AudioDecoder>& decoder,
92 const PipelineStatusCB& init_callback, 93 const PipelineStatusCB& init_callback,
93 const base::Closure& underflow_callback, 94 const base::Closure& underflow_callback,
94 const AudioTimeCB& audio_time_cb) { 95 const AudioTimeCB& audio_time_cb) {
(...skipping 11 matching lines...) Expand all
106 107
107 // Construct the algorithm. 108 // Construct the algorithm.
108 algorithm_.reset(new AudioRendererAlgorithmBase()); 109 algorithm_.reset(new AudioRendererAlgorithmBase());
109 110
110 // Initialize our algorithm with media properties, initial playback rate, 111 // Initialize our algorithm with media properties, initial playback rate,
111 // and a callback to request more reads from the data source. 112 // and a callback to request more reads from the data source.
112 ChannelLayout channel_layout = decoder_->channel_layout(); 113 ChannelLayout channel_layout = decoder_->channel_layout();
113 int channels = ChannelLayoutToChannelCount(channel_layout); 114 int channels = ChannelLayoutToChannelCount(channel_layout);
114 int bits_per_channel = decoder_->bits_per_channel(); 115 int bits_per_channel = decoder_->bits_per_channel();
115 int sample_rate = decoder_->samples_per_second(); 116 int sample_rate = decoder_->samples_per_second();
117 bytes_per_frame_ = channels * bits_per_channel / 8;
116 118
117 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate, 119 bool config_ok = algorithm_->ValidateConfig(channels, sample_rate,
118 bits_per_channel); 120 bits_per_channel);
119 if (config_ok) 121 if (config_ok)
120 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb); 122 algorithm_->Initialize(channels, sample_rate, bits_per_channel, 0.0f, cb);
121 123
122 // Give the subclass an opportunity to initialize itself. 124 // Give the subclass an opportunity to initialize itself.
123 if (!config_ok || !OnInitialize(bits_per_channel, channel_layout, 125 if (!config_ok || !OnInitialize(bits_per_channel, channel_layout,
124 sample_rate)) { 126 sample_rate)) {
125 init_callback.Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 127 init_callback.Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
126 return; 128 return;
127 } 129 }
128 130
129 // Finally, execute the start callback. 131 // Finally, execute the start callback.
130 state_ = kPaused; 132 state_ = kPaused;
131 init_callback.Run(PIPELINE_OK); 133 init_callback.Run(PIPELINE_OK);
132 } 134 }
133 135
134 bool AudioRendererBase::HasEnded() { 136 bool AudioRendererBase::HasEnded() {
135 base::AutoLock auto_lock(lock_); 137 base::AutoLock auto_lock(lock_);
136 if (rendered_end_of_stream_) { 138 if (rendered_end_of_stream_)
137 DCHECK(algorithm_->IsQueueEmpty()) 139 DCHECK(algorithm_->NeedsMoreData() || algorithm_->IsQueueEmpty());
acolwell GONE FROM CHROMIUM 2012/02/22 07:51:40 It seems like we are using the same combination of
vrk (LEFT CHROMIUM) 2012/02/23 20:33:06 Done.
138 << "Audio queue should be empty if we have rendered end of stream"; 140
139 } 141 return received_end_of_stream_ && rendered_end_of_stream_;
140 return recieved_end_of_stream_ && rendered_end_of_stream_;
141 } 142 }
142 143
143 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) { 144 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) {
144 base::AutoLock auto_lock(lock_); 145 base::AutoLock auto_lock(lock_);
145 if (state_ == kUnderflow) { 146 if (state_ == kUnderflow) {
146 if (buffer_more_audio) 147 if (buffer_more_audio)
147 algorithm_->IncreaseQueueCapacity(); 148 algorithm_->IncreaseQueueCapacity();
148 149
149 state_ = kRebuffering; 150 state_ = kRebuffering;
150 } 151 }
151 } 152 }
152 153
153 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) { 154 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) {
154 base::AutoLock auto_lock(lock_); 155 base::AutoLock auto_lock(lock_);
155 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 156 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
156 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); 157 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped);
157 158
158 CHECK(pending_read_); 159 CHECK(pending_read_);
159 pending_read_ = false; 160 pending_read_ = false;
160 161
161 if (buffer && buffer->IsEndOfStream()) { 162 if (buffer && buffer->IsEndOfStream()) {
162 recieved_end_of_stream_ = true; 163 received_end_of_stream_ = true;
163 164
164 // Transition to kPlaying if we are currently handling an underflow since 165 // Transition to kPlaying if we are currently handling an underflow since
165 // no more data will be arriving. 166 // no more data will be arriving.
166 if (state_ == kUnderflow || state_ == kRebuffering) 167 if (state_ == kUnderflow || state_ == kRebuffering)
167 state_ = kPlaying; 168 state_ = kPlaying;
168 } 169 }
169 170
170 switch (state_) { 171 switch (state_) {
171 case kUninitialized: 172 case kUninitialized:
172 NOTREACHED(); 173 NOTREACHED();
(...skipping 22 matching lines...) Expand all
195 case kRebuffering: 196 case kRebuffering:
196 if (buffer && !buffer->IsEndOfStream()) 197 if (buffer && !buffer->IsEndOfStream())
197 algorithm_->EnqueueBuffer(buffer); 198 algorithm_->EnqueueBuffer(buffer);
198 return; 199 return;
199 case kStopped: 200 case kStopped:
200 return; 201 return;
201 } 202 }
202 } 203 }
203 204
204 uint32 AudioRendererBase::FillBuffer(uint8* dest, 205 uint32 AudioRendererBase::FillBuffer(uint8* dest,
205 uint32 dest_len, 206 uint32 requested_frames,
206 const base::TimeDelta& playback_delay) { 207 const base::TimeDelta& playback_delay) {
207 // The timestamp of the last buffer written during the last call to 208 // The timestamp of the last buffer written during the last call to
208 // FillBuffer(). 209 // FillBuffer().
209 base::TimeDelta last_fill_buffer_time; 210 base::TimeDelta last_fill_buffer_time;
210 size_t dest_written = 0; 211 size_t frames_written = 0;
211 base::Closure underflow_cb; 212 base::Closure underflow_cb;
212 { 213 {
213 base::AutoLock auto_lock(lock_); 214 base::AutoLock auto_lock(lock_);
214 215
215 if (state_ == kRebuffering && algorithm_->IsQueueFull()) 216 if (state_ == kRebuffering && algorithm_->IsQueueFull())
216 state_ = kPlaying; 217 state_ = kPlaying;
217 218
218 // Mute audio by returning 0 when not playing. 219 // Mute audio by returning 0 when not playing.
219 if (state_ != kPlaying) { 220 if (state_ != kPlaying) {
220 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of 221 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of
221 // zeros. This gets around the tricky situation of pausing and resuming 222 // zeros. This gets around the tricky situation of pausing and resuming
222 // the audio IPC layer in Chrome. Ideally, we should return zero and then 223 // the audio IPC layer in Chrome. Ideally, we should return zero and then
223 // the subclass can restart the conversation. 224 // the subclass can restart the conversation.
224 // 225 //
225 // This should get handled by the subclass http://crbug.com/106600 226 // This should get handled by the subclass http://crbug.com/106600
226 const uint32 kZeroLength = 8192; 227 const uint32 kZeroLength = 8192;
227 dest_written = std::min(kZeroLength, dest_len); 228 size_t zeros_to_write =
228 memset(dest, 0, dest_written); 229 std::min(kZeroLength, requested_frames * bytes_per_frame_);
229 return dest_written; 230 memset(dest, 0, zeros_to_write);
231 return zeros_to_write / bytes_per_frame_;
230 } 232 }
231 233
232 // Save a local copy of last fill buffer time and reset the member. 234 // Save a local copy of last fill buffer time and reset the member.
233 last_fill_buffer_time = last_fill_buffer_time_; 235 last_fill_buffer_time = last_fill_buffer_time_;
234 last_fill_buffer_time_ = base::TimeDelta(); 236 last_fill_buffer_time_ = base::TimeDelta();
235 237
236 // Use three conditions to determine the end of playback: 238 // Use three conditions to determine the end of playback:
237 // 1. Algorithm has no audio data. (algorithm_->IsQueueEmpty() == true) 239 // 1. Algorithm needs more audio data.
238 // 2. We've recieved an end of stream buffer. 240 // 2. We've received an end of stream buffer.
239 // (recieved_end_of_stream_ == true) 241 // (received_end_of_stream_ == true)
240 // 3. Browser process has no audio data being played. 242 // 3. Browser process has no audio data being played.
241 // There is no way to check that condition that would work for all 243 // There is no way to check that condition that would work for all
242 // derived classes, so call virtual method that would either render 244 // derived classes, so call virtual method that would either render
243 // end of stream or schedule such rendering. 245 // end of stream or schedule such rendering.
244 // 246 //
245 // Three conditions determine when an underflow occurs: 247 // Three conditions determine when an underflow occurs:
246 // 1. Algorithm has no audio data. 248 // 1. Algorithm has no audio data.
247 // 2. Currently in the kPlaying state. 249 // 2. Currently in the kPlaying state.
248 // 3. Have not received an end of stream buffer. 250 // 3. Have not received an end of stream buffer.
249 if (algorithm_->IsQueueEmpty()) { 251 if (algorithm_->IsQueueEmpty() || algorithm_->NeedsMoreData()) {
250 if (recieved_end_of_stream_) { 252 if (received_end_of_stream_) {
251 OnRenderEndOfStream(); 253 OnRenderEndOfStream();
252 } else if (state_ == kPlaying) { 254 } else if (state_ == kPlaying) {
253 state_ = kUnderflow; 255 state_ = kUnderflow;
254 underflow_cb = underflow_callback_; 256 underflow_cb = underflow_callback_;
255 } 257 }
256 } else { 258 } else {
257 // Otherwise fill the buffer. 259 // Otherwise fill the buffer.
258 dest_written = algorithm_->FillBuffer(dest, dest_len); 260 frames_written = algorithm_->FillBuffer(dest, requested_frames);
259 } 261 }
260 262
261 // Get the current time. 263 // Get the current time.
262 last_fill_buffer_time_ = algorithm_->GetTime(); 264 last_fill_buffer_time_ = algorithm_->GetTime();
263 } 265 }
264 266
265 // Update the pipeline's time if it was set last time. 267 // Update the pipeline's time if it was set last time.
266 base::TimeDelta new_current_time = last_fill_buffer_time - playback_delay; 268 base::TimeDelta new_current_time = last_fill_buffer_time - playback_delay;
267 if (last_fill_buffer_time.InMicroseconds() > 0 && 269 if (last_fill_buffer_time.InMicroseconds() > 0 &&
268 (last_fill_buffer_time != last_fill_buffer_time_ || 270 (last_fill_buffer_time != last_fill_buffer_time_ ||
269 new_current_time > host()->GetTime())) { 271 new_current_time > host()->GetTime())) {
270 audio_time_cb_.Run(new_current_time, last_fill_buffer_time); 272 audio_time_cb_.Run(new_current_time, last_fill_buffer_time);
271 } 273 }
272 274
273 if (!underflow_cb.is_null()) 275 if (!underflow_cb.is_null())
274 underflow_cb.Run(); 276 underflow_cb.Run();
275 277
276 return dest_written; 278 return frames_written;
277 } 279 }
278 280
279 void AudioRendererBase::SignalEndOfStream() { 281 void AudioRendererBase::SignalEndOfStream() {
280 DCHECK(recieved_end_of_stream_); 282 DCHECK(received_end_of_stream_);
281 if (!rendered_end_of_stream_) { 283 if (!rendered_end_of_stream_) {
282 rendered_end_of_stream_ = true; 284 rendered_end_of_stream_ = true;
283 host()->NotifyEnded(); 285 host()->NotifyEnded();
284 } 286 }
285 } 287 }
286 288
287 void AudioRendererBase::ScheduleRead_Locked() { 289 void AudioRendererBase::ScheduleRead_Locked() {
288 lock_.AssertAcquired(); 290 lock_.AssertAcquired();
289 if (pending_read_ || state_ == kPaused) 291 if (pending_read_ || state_ == kPaused)
290 return; 292 return;
(...skipping 10 matching lines...) Expand all
301 base::AutoLock auto_lock(lock_); 303 base::AutoLock auto_lock(lock_);
302 return algorithm_->playback_rate(); 304 return algorithm_->playback_rate();
303 } 305 }
304 306
305 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) { 307 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) {
306 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() && 308 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() &&
307 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_; 309 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_;
308 } 310 }
309 311
310 } // namespace media 312 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698