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

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

Powered by Google App Engine
This is Rietveld 408576698