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

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: Simplify! 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"
(...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 23 matching lines...) Expand all
113 111
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); 120 DoStopCloseAndClearStream(NULL);
123 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params_); 121 stream_ = diverting_to_stream_ ? diverting_to_stream_ :
122 audio_manager_->MakeAudioOutputStreamProxy(params_);
124 if (!stream_) { 123 if (!stream_) {
125 state_ = kError; 124 state_ = kError;
126 125
127 // TODO(hclam): Define error types. 126 // TODO(hclam): Define error types.
128 handler_->OnError(this, 0); 127 handler_->OnError(this, 0);
129 return; 128 return;
130 } 129 }
131 130
132 if (!stream_->Open()) { 131 if (!stream_->Open()) {
133 state_ = kError; 132 state_ = kError;
134 DoStopCloseAndClearStream(NULL); 133 DoStopCloseAndClearStream(NULL);
135 134
136 // TODO(hclam): Define error types. 135 // TODO(hclam): Define error types.
137 handler_->OnError(this, 0); 136 handler_->OnError(this, 0);
138 return; 137 return;
139 } 138 }
140 139
141 // Everything started okay, so register for state change callbacks if we have 140 // Everything started okay, so re-register for state change callbacks if
142 // not already done so. 141 // stream_ was created via AudioManager. Note: The call to
143 if (state_ != kRecreating) 142 // DoStopCloseAndClearStream() above called
143 // RemoveOutputDeviceChangeListener().
144 if (stream_ != diverting_to_stream_)
144 audio_manager_->AddOutputDeviceChangeListener(this); 145 audio_manager_->AddOutputDeviceChangeListener(this);
145 146
146 // We have successfully opened the stream. Set the initial volume. 147 // We have successfully opened the stream. Set the initial volume.
147 stream_->SetVolume(volume_); 148 stream_->SetVolume(volume_);
148 149
149 // Finally set the state to kCreated. 150 // Finally set the state to kCreated.
150 State original_state = state_; 151 State original_state = state_;
151 state_ = kCreated; 152 state_ = kCreated;
152 153
153 // And then report we have been created if we haven't done so already. 154 // And then report we have been created if we haven't done so already.
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 // Handle error on the audio controller thread. 342 // Handle error on the audio controller thread.
342 message_loop_->PostTask(FROM_HERE, base::Bind( 343 message_loop_->PostTask(FROM_HERE, base::Bind(
343 &AudioOutputController::DoReportError, this, code)); 344 &AudioOutputController::DoReportError, this, code));
344 } 345 }
345 346
346 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { 347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) {
347 DCHECK(message_loop_->BelongsToCurrentThread()); 348 DCHECK(message_loop_->BelongsToCurrentThread());
348 349
349 // 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.
350 if (stream_) { 351 if (stream_) {
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);
356
351 stream_->Stop(); 357 stream_->Stop();
352 stream_->Close(); 358 stream_->Close();
359 if (stream_ == diverting_to_stream_)
360 diverting_to_stream_ = NULL;
353 stream_ = NULL; 361 stream_ = NULL;
354 362
355 audio_manager_->RemoveOutputDeviceChangeListener(this);
356 audio_manager_ = NULL;
357
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. 374 // Recreate the stream (DoCreate() will first shut down an existing stream).
370 CHECK(stream_); 375 // Exit if we ran into an error.
371 376 const State original_state = state_;
372 // Preserve the original state and shutdown the stream.
373 State original_state = state_;
374 stream_->Stop();
375 stream_->Close();
376 stream_ = NULL;
377
378 // Recreate the stream, exit if we ran into an error.
379 state_ = kRecreating; 377 state_ = kRecreating;
DaleCurtis 2012/12/17 20:00:47 Is this state necessary anymore? Should DoStopClos
miu 2012/12/19 00:22:57 Yes, it's still necessary. The code on line 155 u
380 DoCreate(); 378 DoCreate();
381 if (!stream_ || state_ == kError) 379 if (!stream_ || state_ == kError)
382 return; 380 return;
383 381
384 // Get us back to the original state or an equivalent state. 382 // Get us back to the original state or an equivalent state.
385 switch (original_state) { 383 switch (original_state) {
386 case kStarting: 384 case kStarting:
387 case kPlaying: 385 case kPlaying:
388 DoPlay(); 386 DoPlay();
389 return; 387 return;
390 case kCreated: 388 case kCreated:
391 case kPausedWhenStarting: 389 case kPausedWhenStarting:
392 case kPaused: 390 case kPaused:
393 // From the outside these three states are equivalent. 391 // From the outside these three states are equivalent.
394 return; 392 return;
395 default: 393 default:
396 NOTREACHED() << "Invalid original state."; 394 NOTREACHED() << "Invalid original state.";
397 } 395 }
398 } 396 }
399 397
398 void AudioOutputController::DivertToStream(AudioOutputStream* to_stream) {
399 if (!message_loop_->BelongsToCurrentThread()) {
DaleCurtis 2012/12/17 20:00:47 Which threads will be calling this?
miu 2012/12/19 00:22:57 The IO thread (from AudioRendererHost). Added Thr
400 message_loop_->PostTask(
401 FROM_HERE,
402 base::Bind(&AudioOutputController::DivertToStream, this, to_stream));
403 return;
404 }
405
406 DCHECK(!diverting_to_stream_);
407 diverting_to_stream_ = to_stream;
DaleCurtis 2012/12/17 20:00:47 I suspect this might have issues if it gets fired
miu 2012/12/19 00:22:57 See DCHECK one line down. ;-)
408 DCHECK_NE(kClosed, state_);
409 OnDeviceChange();
410 }
411
412 void AudioOutputController::RevertDiversion() {
413 if (!message_loop_->BelongsToCurrentThread()) {
DaleCurtis 2012/12/17 20:00:47 Ditto.
miu 2012/12/19 00:22:57 Done.
414 message_loop_->PostTask(
415 FROM_HERE, base::Bind(&AudioOutputController::RevertDiversion, this));
416 return;
417 }
418
419 if (state_ != kClosed) {
420 OnDeviceChange();
421 DCHECK(!diverting_to_stream_);
422 }
423 }
424
400 } // namespace media 425 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698