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

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: Move Diverter interface into audio_io.h. Replace use of singleton with BrowserMainLoop. Created 7 years, 11 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/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
(...skipping 11 matching lines...) Expand all
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 AudioOutputController::AudioOutputController(AudioManager* audio_manager, 27 AudioOutputController::AudioOutputController(AudioManager* audio_manager,
28 EventHandler* handler, 28 EventHandler* handler,
29 const AudioParameters& params, 29 const AudioParameters& params,
30 SyncReader* sync_reader) 30 SyncReader* sync_reader)
31 : audio_manager_(audio_manager), 31 : audio_manager_(audio_manager),
32 params_(params),
32 handler_(handler), 33 handler_(handler),
33 stream_(NULL), 34 stream_(NULL),
35 diverting_to_stream_(NULL),
34 volume_(1.0), 36 volume_(1.0),
35 state_(kEmpty), 37 state_(kEmpty),
36 sync_reader_(sync_reader), 38 sync_reader_(sync_reader),
37 message_loop_(audio_manager->GetMessageLoop()), 39 message_loop_(audio_manager->GetMessageLoop()),
38 number_polling_attempts_left_(0), 40 number_polling_attempts_left_(0),
39 params_(params),
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { 41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
41 } 42 }
42 43
43 AudioOutputController::~AudioOutputController() { 44 AudioOutputController::~AudioOutputController() {
44 DCHECK_EQ(kClosed, state_); 45 DCHECK_EQ(kClosed, state_);
45 46
46 if (message_loop_->BelongsToCurrentThread()) { 47 if (message_loop_->BelongsToCurrentThread()) {
47 DoStopCloseAndClearStream(NULL); 48 DoStopCloseAndClearStream(NULL);
48 } else { 49 } else {
49 // http://crbug.com/120973 50 // http://crbug.com/120973
(...skipping 13 matching lines...) Expand all
63 AudioManager* audio_manager, 64 AudioManager* audio_manager,
64 EventHandler* event_handler, 65 EventHandler* event_handler,
65 const AudioParameters& params, 66 const AudioParameters& params,
66 SyncReader* sync_reader) { 67 SyncReader* sync_reader) {
67 DCHECK(audio_manager); 68 DCHECK(audio_manager);
68 DCHECK(sync_reader); 69 DCHECK(sync_reader);
69 70
70 if (!params.IsValid() || !audio_manager) 71 if (!params.IsValid() || !audio_manager)
71 return NULL; 72 return NULL;
72 73
73 // Starts the audio controller thread.
74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 74 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
75 audio_manager, event_handler, params, sync_reader)); 75 audio_manager, event_handler, params, sync_reader));
76
77 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 76 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
78 &AudioOutputController::DoCreate, controller)); 77 &AudioOutputController::DoCreate, controller));
79
80 return controller; 78 return controller;
81 } 79 }
82 80
83 void AudioOutputController::Play() { 81 void AudioOutputController::Play() {
84 DCHECK(message_loop_); 82 DCHECK(message_loop_);
85 message_loop_->PostTask(FROM_HERE, base::Bind( 83 message_loop_->PostTask(FROM_HERE, base::Bind(
86 &AudioOutputController::DoPlay, this)); 84 &AudioOutputController::DoPlay, this));
87 } 85 }
88 86
89 void AudioOutputController::Pause() { 87 void AudioOutputController::Pause() {
(...skipping 24 matching lines...) Expand all
114 void AudioOutputController::DoCreate() { 112 void AudioOutputController::DoCreate() {
115 DCHECK(message_loop_->BelongsToCurrentThread()); 113 DCHECK(message_loop_->BelongsToCurrentThread());
116 114
117 // Close() can be called before DoCreate() is executed. 115 // Close() can be called before DoCreate() is executed.
118 if (state_ == kClosed) 116 if (state_ == kClosed)
119 return; 117 return;
120 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_; 118 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_;
121 119
122 DoStopCloseAndClearStream(NULL); // Calls RemoveOutputDeviceChangeListener(). 120 DoStopCloseAndClearStream(NULL); // Calls RemoveOutputDeviceChangeListener().
123 121
124 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params_); 122 stream_ = diverting_to_stream_ ? diverting_to_stream_ :
123 audio_manager_->MakeAudioOutputStreamProxy(params_);
125 if (!stream_) { 124 if (!stream_) {
126 state_ = kError; 125 state_ = kError;
127 126
128 // TODO(hclam): Define error types. 127 // TODO(hclam): Define error types.
129 handler_->OnError(this, 0); 128 handler_->OnError(this, 0);
130 return; 129 return;
131 } 130 }
132 131
133 if (!stream_->Open()) { 132 if (!stream_->Open()) {
134 state_ = kError; 133 state_ = kError;
135 DoStopCloseAndClearStream(NULL); 134 DoStopCloseAndClearStream(NULL);
136 135
137 // TODO(hclam): Define error types. 136 // TODO(hclam): Define error types.
138 handler_->OnError(this, 0); 137 handler_->OnError(this, 0);
139 return; 138 return;
140 } 139 }
141 140
142 // Everything started okay, so register for state change callbacks if we have 141 // Everything started okay, so re-register for state change callbacks if
143 // not already done so. 142 // stream_ was created via AudioManager.
144 audio_manager_->AddOutputDeviceChangeListener(this); 143 if (stream_ != diverting_to_stream_)
144 audio_manager_->AddOutputDeviceChangeListener(this);
145 145
146 // We have successfully opened the stream. Set the initial volume. 146 // We have successfully opened the stream. Set the initial volume.
147 stream_->SetVolume(volume_); 147 stream_->SetVolume(volume_);
148 148
149 // Finally set the state to kCreated. 149 // Finally set the state to kCreated.
150 State original_state = state_; 150 State original_state = state_;
151 state_ = kCreated; 151 state_ = kCreated;
152 152
153 // And then report we have been created if we haven't done so already. 153 // And then report we have been created if we haven't done so already.
154 if (original_state != kRecreating) 154 if (original_state != kRecreating)
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 int AudioOutputController::OnMoreData(AudioBus* dest, 298 int AudioOutputController::OnMoreData(AudioBus* dest,
299 AudioBuffersState buffers_state) { 299 AudioBuffersState buffers_state) {
300 return OnMoreIOData(NULL, dest, buffers_state); 300 return OnMoreIOData(NULL, dest, buffers_state);
301 } 301 }
302 302
303 int AudioOutputController::OnMoreIOData(AudioBus* source, 303 int AudioOutputController::OnMoreIOData(AudioBus* source,
304 AudioBus* dest, 304 AudioBus* dest,
305 AudioBuffersState buffers_state) { 305 AudioBuffersState buffers_state) {
306 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 306 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
307 307
308 { 308 {
DaleCurtis 2013/01/08 19:23:33 Can you submit the removal CL for this that we dis
miu 2013/01/09 02:19:41 Done. Thanks for reminding me. Link: http://crbu
309 // Check state and do nothing if we are not playing. 309 // Check state and do nothing if we are not playing.
310 // We are on the hardware audio thread, so lock is needed. 310 // We are on the hardware audio thread, so lock is needed.
311 base::AutoLock auto_lock(lock_); 311 base::AutoLock auto_lock(lock_);
312 if (state_ != kPlaying) { 312 if (state_ != kPlaying) {
313 return 0; 313 return 0;
314 } 314 }
315 } 315 }
316 316
317 int frames = sync_reader_->Read(source, dest); 317 int frames = sync_reader_->Read(source, dest);
318 sync_reader_->UpdatePendingBytes( 318 sync_reader_->UpdatePendingBytes(
(...skipping 23 matching lines...) Expand all
342 // Handle error on the audio controller thread. 342 // Handle error on the audio controller thread.
343 message_loop_->PostTask(FROM_HERE, base::Bind( 343 message_loop_->PostTask(FROM_HERE, base::Bind(
344 &AudioOutputController::DoReportError, this, code)); 344 &AudioOutputController::DoReportError, this, code));
345 } 345 }
346 346
347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { 347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) {
348 DCHECK(message_loop_->BelongsToCurrentThread()); 348 DCHECK(message_loop_->BelongsToCurrentThread());
349 349
350 // Allow calling unconditionally and bail if we don't have a stream_ to close. 350 // Allow calling unconditionally and bail if we don't have a stream_ to close.
351 if (stream_) { 351 if (stream_) {
352 audio_manager_->RemoveOutputDeviceChangeListener(this); 352 // De-register from state change callbacks if stream_ was created via
353 // AudioManager.
354 if (stream_ != diverting_to_stream_)
355 audio_manager_->RemoveOutputDeviceChangeListener(this);
353 356
354 stream_->Stop(); 357 stream_->Stop();
355 stream_->Close(); 358 stream_->Close();
359 if (stream_ == diverting_to_stream_)
360 diverting_to_stream_ = NULL;
356 stream_ = NULL; 361 stream_ = NULL;
357 362
358 weak_this_.InvalidateWeakPtrs(); 363 weak_this_.InvalidateWeakPtrs();
359 } 364 }
360 365
361 // Should be last in the method, do not touch "this" from here on. 366 // Should be last in the method, do not touch "this" from here on.
362 if (done) 367 if (done)
363 done->Signal(); 368 done->Signal();
364 } 369 }
365 370
366 void AudioOutputController::OnDeviceChange() { 371 void AudioOutputController::OnDeviceChange() {
367 DCHECK(message_loop_->BelongsToCurrentThread()); 372 DCHECK(message_loop_->BelongsToCurrentThread());
368 373
369 // We should always have a stream by this point.
370 CHECK(stream_);
371
372 // Recreate the stream (DoCreate() will first shut down an existing stream). 374 // Recreate the stream (DoCreate() will first shut down an existing stream).
373 // Exit if we ran into an error. 375 // Exit if we ran into an error.
374 const State original_state = state_; 376 const State original_state = state_;
375 state_ = kRecreating; 377 state_ = kRecreating;
376 DoCreate(); 378 DoCreate();
377 if (!stream_ || state_ == kError) 379 if (!stream_ || state_ == kError)
378 return; 380 return;
379 381
380 // Get us back to the original state or an equivalent state. 382 // Get us back to the original state or an equivalent state.
381 switch (original_state) { 383 switch (original_state) {
382 case kStarting: 384 case kStarting:
383 case kPlaying: 385 case kPlaying:
384 DoPlay(); 386 DoPlay();
385 return; 387 return;
386 case kCreated: 388 case kCreated:
387 case kPausedWhenStarting: 389 case kPausedWhenStarting:
388 case kPaused: 390 case kPaused:
389 // From the outside these three states are equivalent. 391 // From the outside these three states are equivalent.
390 return; 392 return;
391 default: 393 default:
392 NOTREACHED() << "Invalid original state."; 394 NOTREACHED() << "Invalid original state.";
393 } 395 }
394 } 396 }
395 397
398 const AudioParameters& AudioOutputController::GetAudioParameters() {
399 return params_;
400 }
401
402 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
403 message_loop_->PostTask(
404 FROM_HERE,
405 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
406 }
407
408 void AudioOutputController::StopDiverting() {
409 message_loop_->PostTask(
410 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
411 }
412
413 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
414 DCHECK(message_loop_->BelongsToCurrentThread());
415
416 if (state_ == kClosed)
417 return;
418
419 DCHECK(!diverting_to_stream_);
420 diverting_to_stream_ = to_stream;
421 // Note: OnDeviceChange() will engage the "re-create" process, which will
422 // detect and use the alternate AudioOutputStream rather than create a new one
423 // via AudioManager.
424 OnDeviceChange();
425 }
426
427 void AudioOutputController::DoStopDiverting() {
428 DCHECK(message_loop_->BelongsToCurrentThread());
429
430 if (state_ == kClosed)
431 return;
432
433 // Note: OnDeviceChange() will cause the existing stream (the consumer of the
434 // diverted audio data) to be closed, and diverting_to_stream_ will be set
435 // back to NULL.
436 OnDeviceChange();
437 DCHECK(!diverting_to_stream_);
438 }
439
396 } // namespace media 440 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698