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

Side by Side Diff: media/audio/audio_output_controller.cc

Issue 16103007: Privitize WaitTillDataReady() and DataReady(). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Gotta catch'em all! Created 7 years, 6 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
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/audio/audio_output_controller.h" 5 #include "media/audio/audio_output_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 params_(params), 45 params_(params),
46 handler_(handler), 46 handler_(handler),
47 input_device_id_(input_device_id), 47 input_device_id_(input_device_id),
48 stream_(NULL), 48 stream_(NULL),
49 diverting_to_stream_(NULL), 49 diverting_to_stream_(NULL),
50 volume_(1.0), 50 volume_(1.0),
51 state_(kEmpty), 51 state_(kEmpty),
52 num_allowed_io_(0), 52 num_allowed_io_(0),
53 sync_reader_(sync_reader), 53 sync_reader_(sync_reader),
54 message_loop_(audio_manager->GetMessageLoop()), 54 message_loop_(audio_manager->GetMessageLoop()),
55 number_polling_attempts_left_(0), 55 number_polling_attempts_left_(0) {
56 weak_this_(this) {
57 DCHECK(audio_manager); 56 DCHECK(audio_manager);
58 DCHECK(handler_); 57 DCHECK(handler_);
59 DCHECK(sync_reader_); 58 DCHECK(sync_reader_);
60 DCHECK(message_loop_.get()); 59 DCHECK(message_loop_.get());
61 } 60 }
62 61
63 AudioOutputController::~AudioOutputController() { 62 AudioOutputController::~AudioOutputController() {
64 DCHECK_EQ(kClosed, state_); 63 DCHECK_EQ(kClosed, state_);
65 } 64 }
66 65
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 // Finally set the state to kCreated. 141 // Finally set the state to kCreated.
143 state_ = kCreated; 142 state_ = kCreated;
144 143
145 // And then report we have been created if we haven't done so already. 144 // And then report we have been created if we haven't done so already.
146 if (!is_for_device_change) 145 if (!is_for_device_change)
147 handler_->OnCreated(); 146 handler_->OnCreated();
148 } 147 }
149 148
150 void AudioOutputController::DoPlay() { 149 void AudioOutputController::DoPlay() {
151 DCHECK(message_loop_->BelongsToCurrentThread()); 150 DCHECK(message_loop_->BelongsToCurrentThread());
151 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
152 152
153 // We can start from created or paused state. 153 // We can start from created or paused state.
154 if (state_ != kCreated && state_ != kPaused) 154 if (state_ != kCreated && state_ != kPaused)
155 return; 155 return;
156 156
157 state_ = kStarting;
158
159 // Ask for first packet. 157 // Ask for first packet.
160 sync_reader_->UpdatePendingBytes(0); 158 sync_reader_->UpdatePendingBytes(0);
161 159
162 // Cannot start stream immediately, should give renderer some time
163 // to deliver data.
164 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky.
165 // Refine the API such that polling is no longer needed. (crbug.com/112196)
166 number_polling_attempts_left_ = kPollNumAttempts;
167 DCHECK(!weak_this_.HasWeakPtrs());
168 message_loop_->PostDelayedTask(
169 FROM_HERE,
170 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
171 weak_this_.GetWeakPtr()),
172 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
173 }
174
175 void AudioOutputController::PollAndStartIfDataReady() {
176 DCHECK(message_loop_->BelongsToCurrentThread());
177 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
178
179 DCHECK_EQ(kStarting, state_);
180
181 // If we are ready to start the stream, start it.
182 if (--number_polling_attempts_left_ == 0 ||
183 sync_reader_->DataReady()) {
184 StartStream();
185 } else {
186 message_loop_->PostDelayedTask(
187 FROM_HERE,
188 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
189 weak_this_.GetWeakPtr()),
190 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
191 }
192 }
193
194 void AudioOutputController::StartStream() {
195 DCHECK(message_loop_->BelongsToCurrentThread());
196 state_ = kPlaying; 160 state_ = kPlaying;
197
198 silence_detector_.reset(new AudioSilenceDetector( 161 silence_detector_.reset(new AudioSilenceDetector(
199 params_.sample_rate(), 162 params_.sample_rate(),
200 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), 163 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis),
201 kIndistinguishableSilenceThreshold)); 164 kIndistinguishableSilenceThreshold));
202 165
203 // We start the AudioOutputStream lazily. 166 // We start the AudioOutputStream lazily.
204 AllowEntryToOnMoreIOData(); 167 AllowEntryToOnMoreIOData();
205 stream_->Start(this); 168 stream_->Start(this);
206 169
207 // Tell the event handler that we are now playing, and also start the silence 170 // Tell the event handler that we are now playing, and also start the silence
208 // detection notifications. 171 // detection notifications.
209 handler_->OnPlaying(); 172 handler_->OnPlaying();
210 silence_detector_->Start( 173 silence_detector_->Start(
211 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); 174 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_)));
212 } 175 }
213 176
214 void AudioOutputController::StopStream() { 177 void AudioOutputController::StopStream() {
215 DCHECK(message_loop_->BelongsToCurrentThread()); 178 DCHECK(message_loop_->BelongsToCurrentThread());
216 179
217 if (state_ == kStarting) { 180 if (state_ == kPlaying) {
218 // Cancel in-progress polling start.
219 weak_this_.InvalidateWeakPtrs();
220 state_ = kPaused;
221 } else if (state_ == kPlaying) {
222 stream_->Stop(); 181 stream_->Stop();
223 DisallowEntryToOnMoreIOData(); 182 DisallowEntryToOnMoreIOData();
224 silence_detector_->Stop(true); 183 silence_detector_->Stop(true);
225 silence_detector_.reset(); 184 silence_detector_.reset();
226 state_ = kPaused; 185 state_ = kPaused;
227 } 186 }
228 } 187 }
229 188
230 void AudioOutputController::DoPause() { 189 void AudioOutputController::DoPause() {
231 DCHECK(message_loop_->BelongsToCurrentThread()); 190 DCHECK(message_loop_->BelongsToCurrentThread());
(...skipping 23 matching lines...) Expand all
255 214
256 void AudioOutputController::DoSetVolume(double volume) { 215 void AudioOutputController::DoSetVolume(double volume) {
257 DCHECK(message_loop_->BelongsToCurrentThread()); 216 DCHECK(message_loop_->BelongsToCurrentThread());
258 217
259 // Saves the volume to a member first. We may not be able to set the volume 218 // Saves the volume to a member first. We may not be able to set the volume
260 // right away but when the stream is created we'll set the volume. 219 // right away but when the stream is created we'll set the volume.
261 volume_ = volume; 220 volume_ = volume;
262 221
263 switch (state_) { 222 switch (state_) {
264 case kCreated: 223 case kCreated:
265 case kStarting:
266 case kPlaying: 224 case kPlaying:
267 case kPaused: 225 case kPaused:
268 stream_->SetVolume(volume_); 226 stream_->SetVolume(volume_);
269 break; 227 break;
270 default: 228 default:
271 return; 229 return;
272 } 230 }
273 } 231 }
274 232
275 void AudioOutputController::DoReportError() { 233 void AudioOutputController::DoReportError() {
276 DCHECK(message_loop_->BelongsToCurrentThread()); 234 DCHECK(message_loop_->BelongsToCurrentThread());
277 if (state_ != kClosed) 235 if (state_ != kClosed)
278 handler_->OnError(); 236 handler_->OnError();
279 } 237 }
280 238
281 int AudioOutputController::OnMoreData(AudioBus* dest, 239 int AudioOutputController::OnMoreData(AudioBus* dest,
282 AudioBuffersState buffers_state) { 240 AudioBuffersState buffers_state) {
283 return OnMoreIOData(NULL, dest, buffers_state); 241 return OnMoreIOData(NULL, dest, buffers_state);
284 } 242 }
285 243
286 int AudioOutputController::OnMoreIOData(AudioBus* source, 244 int AudioOutputController::OnMoreIOData(AudioBus* source,
287 AudioBus* dest, 245 AudioBus* dest,
288 AudioBuffersState buffers_state) { 246 AudioBuffersState buffers_state) {
289 DisallowEntryToOnMoreIOData(); 247 DisallowEntryToOnMoreIOData();
290 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 248 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
291 249
292 // The OS level audio APIs on Linux and Windows all have problems requesting 250 // The OS level audio APIs on Linux and Windows all have problems requesting
293 // data on a fixed interval. Sometimes they will issue calls back to back 251 // data on a fixed interval. Sometimes they will issue calls back to back
294 // which can cause glitching, so wait until the renderer is ready for Read(). 252 // which can cause glitching, so wait until the renderer is ready.
253 //
254 // We also need to wait when diverting since the virtual stream will call this
255 // multiple times without waiting.
256 //
257 // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
258 // end up hanging the entire OS.
295 // 259 //
296 // See many bugs for context behind this decision: http://crbug.com/170498, 260 // See many bugs for context behind this decision: http://crbug.com/170498,
297 // http://crbug.com/171651, http://crbug.com/174985, and more. 261 // http://crbug.com/171651, http://crbug.com/174985, and more.
298 #if defined(OS_WIN) || defined(OS_LINUX) 262 #if defined(OS_WIN) || defined(OS_LINUX)
299 WaitTillDataReady(); 263 const bool kShouldBlock = true;
264 #else
265 const bool kShouldBlock = diverting_to_stream_ != NULL;
300 #endif 266 #endif
301 267
302 const int frames = sync_reader_->Read(source, dest); 268 const int frames = sync_reader_->Read(kShouldBlock, source, dest);
303 DCHECK_LE(0, frames); 269 DCHECK_LE(0, frames);
304 sync_reader_->UpdatePendingBytes( 270 sync_reader_->UpdatePendingBytes(
305 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 271 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
306 272
307 silence_detector_->Scan(dest, frames); 273 silence_detector_->Scan(dest, frames);
308 274
309 AllowEntryToOnMoreIOData(); 275 AllowEntryToOnMoreIOData();
310 return frames; 276 return frames;
311 } 277 }
312 278
313 void AudioOutputController::WaitTillDataReady() {
314 // Most of the time the data is ready already.
315 if (sync_reader_->DataReady())
316 return;
317
318 base::TimeTicks start = base::TimeTicks::Now();
319 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20);
320 #if defined(OS_WIN)
321 // Sleep(0) on windows lets the other threads run.
322 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0);
323 #else
324 // We want to sleep for a bit here, as otherwise a backgrounded renderer won't
325 // get enough cpu to send the data and the high priority thread in the browser
326 // will use up a core causing even more skips.
327 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2);
328 #endif
329 base::TimeDelta time_since_start;
330 do {
331 base::PlatformThread::Sleep(kSleep);
332 time_since_start = base::TimeTicks::Now() - start;
333 } while (!sync_reader_->DataReady() && (time_since_start < kMaxWait));
334 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
335 time_since_start,
336 base::TimeDelta::FromMilliseconds(1),
337 base::TimeDelta::FromMilliseconds(1000),
338 50);
339 }
340
341 void AudioOutputController::OnError(AudioOutputStream* stream) { 279 void AudioOutputController::OnError(AudioOutputStream* stream) {
342 // Handle error on the audio controller thread. 280 // Handle error on the audio controller thread.
343 message_loop_->PostTask(FROM_HERE, base::Bind( 281 message_loop_->PostTask(FROM_HERE, base::Bind(
344 &AudioOutputController::DoReportError, this)); 282 &AudioOutputController::DoReportError, this));
345 } 283 }
346 284
347 void AudioOutputController::DoStopCloseAndClearStream() { 285 void AudioOutputController::DoStopCloseAndClearStream() {
348 DCHECK(message_loop_->BelongsToCurrentThread()); 286 DCHECK(message_loop_->BelongsToCurrentThread());
349 287
350 // Allow calling unconditionally and bail if we don't have a stream_ to close. 288 // Allow calling unconditionally and bail if we don't have a stream_ to close.
(...skipping 23 matching lines...) Expand all
374 312
375 // Recreate the stream (DoCreate() will first shut down an existing stream). 313 // Recreate the stream (DoCreate() will first shut down an existing stream).
376 // Exit if we ran into an error. 314 // Exit if we ran into an error.
377 const State original_state = state_; 315 const State original_state = state_;
378 DoCreate(true); 316 DoCreate(true);
379 if (!stream_ || state_ == kError) 317 if (!stream_ || state_ == kError)
380 return; 318 return;
381 319
382 // Get us back to the original state or an equivalent state. 320 // Get us back to the original state or an equivalent state.
383 switch (original_state) { 321 switch (original_state) {
384 case kStarting:
385 case kPlaying: 322 case kPlaying:
386 DoPlay(); 323 DoPlay();
387 return; 324 return;
388 case kCreated: 325 case kCreated:
389 case kPaused: 326 case kPaused:
390 // From the outside these two states are equivalent. 327 // From the outside these two states are equivalent.
391 return; 328 return;
392 default: 329 default:
393 NOTREACHED() << "Invalid original state."; 330 NOTREACHED() << "Invalid original state.";
394 } 331 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); 377 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
441 base::AtomicRefCountInc(&num_allowed_io_); 378 base::AtomicRefCountInc(&num_allowed_io_);
442 } 379 }
443 380
444 void AudioOutputController::DisallowEntryToOnMoreIOData() { 381 void AudioOutputController::DisallowEntryToOnMoreIOData() {
445 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); 382 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
446 DCHECK(is_zero); 383 DCHECK(is_zero);
447 } 384 }
448 385
449 } // namespace media 386 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698