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

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

Issue 11413078: Tab Audio Capture: Browser-side connect/disconnect functionality. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moved Glue to cc file, and renamed to SourceSharingCallback. Created 8 years 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/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/platform_thread.h" 11 #include "base/threading/platform_thread.h"
12 #include "base/threading/thread_restrictions.h" 12 #include "base/threading/thread_restrictions.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "build/build_config.h" 14 #include "build/build_config.h"
15 #include "media/audio/shared_memory_util.h" 15 #include "media/audio/shared_memory_util.h"
16 16
17 using base::Time; 17 using base::Time;
18 using base::TimeDelta; 18 using base::TimeDelta;
19 using base::WaitableEvent; 19 using base::WaitableEvent;
20 20
21 namespace media { 21 namespace media {
22 22
23 // Polling-related constants. 23 // Polling-related constants.
24 const int AudioOutputController::kPollNumAttempts = 3; 24 const int AudioOutputController::kPollNumAttempts = 3;
25 const int AudioOutputController::kPollPauseInMilliseconds = 3; 25 const int AudioOutputController::kPollPauseInMilliseconds = 3;
26 26
27 // An AudioSourceCallback that allows passing around the underlying SyncReader
28 // data source between consumers of the data. It does this in a "pass or
29 // delayed pass" scheme that ensures synchronization between timing-sensitive
30 // threads is effectively non-blocking. In addition, SourceSharingCallback
31 // ensures that only one consumer is pulling data from the SyncReader at a time.
32 class AudioOutputController::SourceSharingCallback
33 : public AudioOutputStream::AudioSourceCallback,
34 public base::RefCountedThreadSafe<SourceSharingCallback> {
35 public:
36 SourceSharingCallback(AudioOutputController* controller, SyncReader* source);
37
38 // Pass the SyncReader to another instance as soon as possible.
39 void PassSoon(const scoped_refptr<SourceSharingCallback>& receiver);
40
41 // AudioSourceCallback implementation.
42 virtual int OnMoreData(AudioBus* dest_bus,
43 AudioBuffersState buffers_state) OVERRIDE;
44 virtual int OnMoreIOData(AudioBus* source_bus,
45 AudioBus* dest_bus,
46 AudioBuffersState buffers_state) OVERRIDE;
47 virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE;
48 virtual void WaitTillDataReady() OVERRIDE;
49
50 private:
51 friend class base::RefCountedThreadSafe<SourceSharingCallback>;
52 virtual ~SourceSharingCallback();
53
54 // Take over reading from |source|.
55 void ReceiveSource(SyncReader* source);
56
57 // Executes a delayed pass (i.e., a pass that was delayed because source_ was
58 // in-use at the time PassSoon() was called).
59 void DoDelayedPassWithLockHeld(
60 const scoped_refptr<SourceSharingCallback>& to);
61
62 // Access to parent/owner instance.
63 AudioOutputController* const controller_;
64
65 // Guards passing of SyncReader to another SourceSharingCallback instance.
66 // The implementation should acquire lock_ for only very short operations
67 // since audio threads are timing-sensitive.
68 base::Lock lock_;
69
70 // Audio data source, or NULL if none yet.
71 SyncReader* source_;
72
73 // True while source_ is in-use without lock_ held.
74 bool is_reading_from_source_;
75
76 // When !delayed_pass_.is_null(), source_ is scheduled to be passed as soon as
77 // possible.
78 base::Closure delayed_pass_;
79
80 DISALLOW_COPY_AND_ASSIGN(SourceSharingCallback);
81 };
82
27 AudioOutputController::AudioOutputController(AudioManager* audio_manager, 83 AudioOutputController::AudioOutputController(AudioManager* audio_manager,
28 EventHandler* handler, 84 EventHandler* handler,
29 const AudioParameters& params, 85 const AudioParameters& params,
30 SyncReader* sync_reader) 86 SyncReader* sync_reader)
31 : audio_manager_(audio_manager), 87 : audio_manager_(audio_manager),
88 params_(params),
32 handler_(handler), 89 handler_(handler),
33 stream_(NULL), 90 stream_(NULL),
91 callback_for_stream_(new SourceSharingCallback(this, sync_reader)),
34 volume_(1.0), 92 volume_(1.0),
35 state_(kEmpty), 93 state_(kEmpty),
36 sync_reader_(sync_reader), 94 sync_reader_(sync_reader),
37 message_loop_(audio_manager->GetMessageLoop()), 95 message_loop_(audio_manager->GetMessageLoop()),
38 number_polling_attempts_left_(0), 96 number_polling_attempts_left_(0),
39 params_(params),
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { 97 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
41 } 98 }
42 99
43 AudioOutputController::~AudioOutputController() { 100 AudioOutputController::~AudioOutputController() {
44 DCHECK_EQ(kClosed, state_); 101 DCHECK_EQ(kClosed, state_);
45 102
46 if (message_loop_->BelongsToCurrentThread()) { 103 if (message_loop_->BelongsToCurrentThread()) {
47 DoStopCloseAndClearStream(NULL); 104 DoStopCloseAndClearStream(NULL);
48 } else { 105 } else {
49 // http://crbug.com/120973 106 // http://crbug.com/120973
(...skipping 13 matching lines...) Expand all
63 AudioManager* audio_manager, 120 AudioManager* audio_manager,
64 EventHandler* event_handler, 121 EventHandler* event_handler,
65 const AudioParameters& params, 122 const AudioParameters& params,
66 SyncReader* sync_reader) { 123 SyncReader* sync_reader) {
67 DCHECK(audio_manager); 124 DCHECK(audio_manager);
68 DCHECK(sync_reader); 125 DCHECK(sync_reader);
69 126
70 if (!params.IsValid() || !audio_manager) 127 if (!params.IsValid() || !audio_manager)
71 return NULL; 128 return NULL;
72 129
73 // Starts the audio controller thread.
74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 130 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
75 audio_manager, event_handler, params, sync_reader)); 131 audio_manager, event_handler, params, sync_reader));
76
77 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 132 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
78 &AudioOutputController::DoCreate, controller)); 133 &AudioOutputController::DoCreate, controller));
79
80 return controller; 134 return controller;
81 } 135 }
82 136
83 void AudioOutputController::Play() { 137 void AudioOutputController::Play() {
84 DCHECK(message_loop_); 138 DCHECK(message_loop_);
85 message_loop_->PostTask(FROM_HERE, base::Bind( 139 message_loop_->PostTask(FROM_HERE, base::Bind(
86 &AudioOutputController::DoPlay, this)); 140 &AudioOutputController::DoPlay, this));
87 } 141 }
88 142
89 void AudioOutputController::Pause() { 143 void AudioOutputController::Pause() {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 185
132 if (!stream_->Open()) { 186 if (!stream_->Open()) {
133 state_ = kError; 187 state_ = kError;
134 DoStopCloseAndClearStream(NULL); 188 DoStopCloseAndClearStream(NULL);
135 189
136 // TODO(hclam): Define error types. 190 // TODO(hclam): Define error types.
137 handler_->OnError(this, 0); 191 handler_->OnError(this, 0);
138 return; 192 return;
139 } 193 }
140 194
141 // Everything started okay, so register for state change callbacks if we have 195 // Everything started okay, so re-register for state change callbacks. Note:
142 // not already done so. 196 // The call to DoStopCloseAndClearStream() above called
143 if (state_ != kRecreating) 197 // RemoveOutputDeviceChangeListener().
144 audio_manager_->AddOutputDeviceChangeListener(this); 198 audio_manager_->AddOutputDeviceChangeListener(this);
145 199
146 // We have successfully opened the stream. Set the initial volume. 200 // We have successfully opened the stream. Set the initial volume.
147 stream_->SetVolume(volume_); 201 stream_->SetVolume(volume_);
148 202
149 // Finally set the state to kCreated. 203 // Finally set the state to kCreated.
150 State original_state = state_; 204 State original_state = state_;
151 state_ = kCreated; 205 state_ = kCreated;
152 206
153 // And then report we have been created if we haven't done so already. 207 // And then report we have been created if we haven't done so already.
154 if (original_state != kRecreating) 208 if (original_state != kRecreating)
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 weak_this_.GetWeakPtr()), 262 weak_this_.GetWeakPtr()),
209 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 263 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
210 } 264 }
211 } 265 }
212 266
213 void AudioOutputController::StartStream() { 267 void AudioOutputController::StartStream() {
214 DCHECK(message_loop_->BelongsToCurrentThread()); 268 DCHECK(message_loop_->BelongsToCurrentThread());
215 state_ = kPlaying; 269 state_ = kPlaying;
216 270
217 // We start the AudioOutputStream lazily. 271 // We start the AudioOutputStream lazily.
218 stream_->Start(this); 272 stream_->Start(callback_for_stream_);
219 273
220 // Tell the event handler that we are now playing. 274 // Tell the event handler that we are now playing.
221 handler_->OnPlaying(this); 275 handler_->OnPlaying(this);
222 } 276 }
223 277
224 void AudioOutputController::DoPause() { 278 void AudioOutputController::DoPause() {
225 DCHECK(message_loop_->BelongsToCurrentThread()); 279 DCHECK(message_loop_->BelongsToCurrentThread());
226 280
227 if (stream_) { 281 if (stream_) {
228 // Then we stop the audio device. This is not the perfect solution 282 // Then we stop the audio device. This is not the perfect solution
(...skipping 26 matching lines...) Expand all
255 void AudioOutputController::DoFlush() { 309 void AudioOutputController::DoFlush() {
256 DCHECK(message_loop_->BelongsToCurrentThread()); 310 DCHECK(message_loop_->BelongsToCurrentThread());
257 311
258 // TODO(hclam): Actually flush the audio device. 312 // TODO(hclam): Actually flush the audio device.
259 } 313 }
260 314
261 void AudioOutputController::DoClose() { 315 void AudioOutputController::DoClose() {
262 DCHECK(message_loop_->BelongsToCurrentThread()); 316 DCHECK(message_loop_->BelongsToCurrentThread());
263 317
264 if (state_ != kClosed) { 318 if (state_ != kClosed) {
319 DCHECK(!callback_for_divert_);
265 DoStopCloseAndClearStream(NULL); 320 DoStopCloseAndClearStream(NULL);
266 sync_reader_->Close(); 321 sync_reader_->Close();
267 state_ = kClosed; 322 state_ = kClosed;
268 } 323 }
269 } 324 }
270 325
271 void AudioOutputController::DoSetVolume(double volume) { 326 void AudioOutputController::DoSetVolume(double volume) {
272 DCHECK(message_loop_->BelongsToCurrentThread()); 327 DCHECK(message_loop_->BelongsToCurrentThread());
273 328
274 // Saves the volume to a member first. We may not be able to set the volume 329 // Saves the volume to a member first. We may not be able to set the volume
(...skipping 12 matching lines...) Expand all
287 return; 342 return;
288 } 343 }
289 } 344 }
290 345
291 void AudioOutputController::DoReportError(int code) { 346 void AudioOutputController::DoReportError(int code) {
292 DCHECK(message_loop_->BelongsToCurrentThread()); 347 DCHECK(message_loop_->BelongsToCurrentThread());
293 if (state_ != kClosed) 348 if (state_ != kClosed)
294 handler_->OnError(this, code); 349 handler_->OnError(this, code);
295 } 350 }
296 351
297 int AudioOutputController::OnMoreData(AudioBus* dest, 352 AudioOutputController::SourceSharingCallback::SourceSharingCallback(
298 AudioBuffersState buffers_state) { 353 AudioOutputController* controller, SyncReader* source)
299 return OnMoreIOData(NULL, dest, buffers_state); 354 : controller_(controller),
355 source_(source),
356 is_reading_from_source_(false) {
300 } 357 }
301 358
302 int AudioOutputController::OnMoreIOData(AudioBus* source, 359 AudioOutputController::SourceSharingCallback::~SourceSharingCallback() {
303 AudioBus* dest, 360 }
304 AudioBuffersState buffers_state) { 361
362 void AudioOutputController::SourceSharingCallback::PassSoon(
363 const scoped_refptr<SourceSharingCallback>& to) {
364 DCHECK_NE(this, to);
365
366 SyncReader* pass_me;
367 {
368 base::AutoLock auto_lock(lock_);
369
370 // Two reasons to delay a pass: 1) another thread is currently reading from
371 // source_; 2) this instance is hasn't received source_ yet.
372 if (is_reading_from_source_ || !source_) {
373 DCHECK(delayed_pass_.is_null()) << "BUG: Attempt to pass twice.";
374 delayed_pass_ = base::Bind(
375 &SourceSharingCallback::DoDelayedPassWithLockHeld, this, to);
376 return;
377 }
378
379 pass_me = source_;
380 source_ = NULL;
381 }
382
383 // Normal path: Pass source_ immediately.
384 to->ReceiveSource(pass_me);
385 }
386
387 void AudioOutputController::SourceSharingCallback::ReceiveSource(
388 SyncReader* source) {
389 base::AutoLock auto_lock(lock_);
390
391 // Accept the audio data source.
392 DCHECK(!source_)
393 << "BUG: Attempt to receive while already holding a SyncReader.";
394 source_ = source;
395
396 // Execute a delayed pass if PassSoon() scheduled one.
397 if (!delayed_pass_.is_null()) {
398 delayed_pass_.Run();
399 delayed_pass_.Reset();
400 }
401 }
402
403 void AudioOutputController::SourceSharingCallback::DoDelayedPassWithLockHeld(
404 const scoped_refptr<SourceSharingCallback>& to) {
405 lock_.AssertAcquired();
406
407 // Pass the SyncReader to another SourceSharingCallback instance, but do not
408 // allow the current thread to block on this action.
409 controller_->message_loop_->PostTask(
410 FROM_HERE,
411 base::Bind(&SourceSharingCallback::ReceiveSource, to, source_));
412 source_ = NULL;
413 }
414
415 int AudioOutputController::SourceSharingCallback::OnMoreData(
416 AudioBus* dest_bus, AudioBuffersState buffers_state) {
417 return OnMoreIOData(NULL, dest_bus, buffers_state);
418 }
419
420 int AudioOutputController::SourceSharingCallback::OnMoreIOData(
421 AudioBus* source_bus, AudioBus* dest_bus, AudioBuffersState buffers_state) {
305 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 422 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
306 423
424 // Attempt to read from the SyncReader. While reading, do not hold lock_.
425 // After reading, acquire the lock again; and execute a delayed pass, if
426 // scheduled.
307 { 427 {
308 // Check state and do nothing if we are not playing.
309 // We are on the hardware audio thread, so lock is needed.
310 base::AutoLock auto_lock(lock_); 428 base::AutoLock auto_lock(lock_);
311 if (state_ != kPlaying) { 429 if (source_ && controller_->state_ == kPlaying) {
312 return 0; 430 is_reading_from_source_ = true;
431 int frames_read;
432 {
433 base::AutoUnlock unlock_while_reading(lock_);
434 frames_read = source_->Read(source_bus, dest_bus);
435 source_->UpdatePendingBytes(
436 buffers_state.total_bytes() +
437 frames_read * controller_->params_.GetBytesPerFrame());
438 }
439 is_reading_from_source_ = false;
440 if (!delayed_pass_.is_null()) {
441 delayed_pass_.Run();
442 delayed_pass_.Reset();
443 }
444 return frames_read;
313 } 445 }
314 } 446 }
315 447
316 int frames = sync_reader_->Read(source, dest); 448 // We haven't received the SyncReader yet, so fill the destination with zeros.
317 sync_reader_->UpdatePendingBytes( 449 dest_bus->Zero();
318 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 450 return dest_bus->frames();
319 return frames;
320 } 451 }
321 452
322 void AudioOutputController::WaitTillDataReady() { 453 void AudioOutputController::SourceSharingCallback::WaitTillDataReady() {
323 #if defined(OS_WIN) || defined(OS_MACOSX) 454 #if defined(OS_WIN) || defined(OS_MACOSX)
324 base::Time start = base::Time::Now(); 455 base::Time start = base::Time::Now();
325 // Wait for up to 1.5 seconds for DataReady(). 1.5 seconds was chosen because 456 // Wait for up to 1.5 seconds for DataReady(). 1.5 seconds was chosen because
326 // it's larger than the playback time of the WaveOut buffer size using the 457 // it's larger than the playback time of the WaveOut buffer size using the
327 // minimum supported sample rate: 4096 / 3000 = ~1.4 seconds. Even a client 458 // minimum supported sample rate: 4096 / 3000 = ~1.4 seconds. Even a client
328 // expecting real time playout should be able to fill in this time. 459 // expecting real time playout should be able to fill in this time.
329 const base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(1500); 460 const base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(1500);
330 while (!sync_reader_->DataReady() && 461 base::AutoLock auto_lock(lock_);
462 while (source_ && !source_->DataReady() &&
331 ((base::Time::Now() - start) < max_wait)) { 463 ((base::Time::Now() - start) < max_wait)) {
464 base::AutoUnlock unlock_while_yielding(lock_);
332 base::PlatformThread::YieldCurrentThread(); 465 base::PlatformThread::YieldCurrentThread();
333 } 466 }
334 #else 467 #else
335 // WaitTillDataReady() is deprecated and should not be used. 468 // WaitTillDataReady() is deprecated and should not be used.
336 CHECK(false); 469 CHECK(false);
337 #endif 470 #endif
338 } 471 }
339 472
340 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { 473 void AudioOutputController::SourceSharingCallback::OnError(
474 AudioOutputStream* stream, int code) {
341 // Handle error on the audio controller thread. 475 // Handle error on the audio controller thread.
342 message_loop_->PostTask(FROM_HERE, base::Bind( 476 controller_->message_loop_->PostTask(FROM_HERE, base::Bind(
343 &AudioOutputController::DoReportError, this, code)); 477 &AudioOutputController::DoReportError, controller_, code));
344 } 478 }
345 479
346 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { 480 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) {
347 DCHECK(message_loop_->BelongsToCurrentThread()); 481 DCHECK(message_loop_->BelongsToCurrentThread());
348 482
349 // Allow calling unconditionally and bail if we don't have a stream_ to close. 483 // Allow calling unconditionally and bail if we don't have a stream_ to close.
350 if (stream_) { 484 if (stream_) {
351 stream_->Stop(); 485 stream_->Stop();
352 stream_->Close(); 486 stream_->Close();
353 stream_ = NULL; 487 stream_ = NULL;
354 488
355 audio_manager_->RemoveOutputDeviceChangeListener(this); 489 audio_manager_->RemoveOutputDeviceChangeListener(this);
356 audio_manager_ = NULL;
357 490
358 weak_this_.InvalidateWeakPtrs(); 491 weak_this_.InvalidateWeakPtrs();
359 } 492 }
360 493
361 // Should be last in the method, do not touch "this" from here on. 494 // Should be last in the method, do not touch "this" from here on.
362 if (done) 495 if (done)
363 done->Signal(); 496 done->Signal();
364 } 497 }
365 498
366 void AudioOutputController::OnDeviceChange() { 499 void AudioOutputController::OnDeviceChange() {
367 DCHECK(message_loop_->BelongsToCurrentThread()); 500 DCHECK(message_loop_->BelongsToCurrentThread());
368 501
369 // We should always have a stream by this point. 502 // We should always have a stream by this point.
370 CHECK(stream_); 503 CHECK(stream_);
371 504
372 // Preserve the original state and shutdown the stream. 505 // Preserve the original state.
373 State original_state = state_; 506 const State original_state = state_;
374 stream_->Stop();
375 stream_->Close();
376 stream_ = NULL;
377 507
378 // Recreate the stream, exit if we ran into an error. 508 // Recreate the stream (DoCreate() will first shut down an existing stream).
509 // Exit if we ran into an error.
379 state_ = kRecreating; 510 state_ = kRecreating;
380 DoCreate(); 511 DoCreate();
381 if (!stream_ || state_ == kError) 512 if (!stream_ || state_ == kError)
382 return; 513 return;
383 514
384 // Get us back to the original state or an equivalent state. 515 // Get us back to the original state or an equivalent state.
385 switch (original_state) { 516 switch (original_state) {
386 case kStarting: 517 case kStarting:
387 case kPlaying: 518 case kPlaying:
519 DoSetVolume(volume_);
388 DoPlay(); 520 DoPlay();
389 return; 521 return;
390 case kCreated: 522 case kCreated:
391 case kPausedWhenStarting: 523 case kPausedWhenStarting:
392 case kPaused: 524 case kPaused:
393 // From the outside these three states are equivalent. 525 // From the outside these three states are equivalent.
394 return; 526 return;
395 default: 527 default:
396 NOTREACHED() << "Invalid original state."; 528 NOTREACHED() << "Invalid original state.";
397 } 529 }
398 } 530 }
399 531
532 AudioOutputStream::AudioSourceCallback* AudioOutputController::Divert() {
533 DCHECK(!callback_for_divert_) << "BUG: Already diverted!";
534 callback_for_divert_ = new SourceSharingCallback(this, NULL);
535 callback_for_stream_->PassSoon(callback_for_divert_);
536 return callback_for_divert_;
537 }
538
539 void AudioOutputController::Revert(
540 AudioOutputStream::AudioSourceCallback* asc) {
541 DCHECK_EQ(callback_for_divert_, asc);
542 callback_for_divert_->PassSoon(callback_for_stream_);
543 callback_for_divert_ = NULL;
544 }
545
400 } // namespace media 546 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698