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

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: Addressed tommi's comments (dependency injection for testing AudioMirroringManager). 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)) {
42 // This thread-checker is only used to ensure calls to StartDiverting() and
43 // StopDiverting() are made by the same single outside thread.
44 divert_thread_checker_.DetachFromThread();
41 } 45 }
42 46
43 AudioOutputController::~AudioOutputController() { 47 AudioOutputController::~AudioOutputController() {
44 DCHECK_EQ(kClosed, state_); 48 DCHECK_EQ(kClosed, state_);
45 49
46 if (message_loop_->BelongsToCurrentThread()) { 50 if (message_loop_->BelongsToCurrentThread()) {
47 DoStopCloseAndClearStream(NULL); 51 DoStopCloseAndClearStream(NULL);
48 } else { 52 } else {
49 // http://crbug.com/120973 53 // http://crbug.com/120973
50 base::ThreadRestrictions::ScopedAllowWait allow_wait; 54 base::ThreadRestrictions::ScopedAllowWait allow_wait;
(...skipping 12 matching lines...) Expand all
63 AudioManager* audio_manager, 67 AudioManager* audio_manager,
64 EventHandler* event_handler, 68 EventHandler* event_handler,
65 const AudioParameters& params, 69 const AudioParameters& params,
66 SyncReader* sync_reader) { 70 SyncReader* sync_reader) {
67 DCHECK(audio_manager); 71 DCHECK(audio_manager);
68 DCHECK(sync_reader); 72 DCHECK(sync_reader);
69 73
70 if (!params.IsValid() || !audio_manager) 74 if (!params.IsValid() || !audio_manager)
71 return NULL; 75 return NULL;
72 76
73 // Starts the audio controller thread.
74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 77 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
75 audio_manager, event_handler, params, sync_reader)); 78 audio_manager, event_handler, params, sync_reader));
76
77 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 79 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
78 &AudioOutputController::DoCreate, controller)); 80 &AudioOutputController::DoCreate, controller));
79
80 return controller; 81 return controller;
81 } 82 }
82 83
83 void AudioOutputController::Play() { 84 void AudioOutputController::Play() {
84 DCHECK(message_loop_); 85 DCHECK(message_loop_);
85 message_loop_->PostTask(FROM_HERE, base::Bind( 86 message_loop_->PostTask(FROM_HERE, base::Bind(
86 &AudioOutputController::DoPlay, this)); 87 &AudioOutputController::DoPlay, this));
87 } 88 }
88 89
89 void AudioOutputController::Pause() { 90 void AudioOutputController::Pause() {
(...skipping 23 matching lines...) Expand all
113 114
114 void AudioOutputController::DoCreate() { 115 void AudioOutputController::DoCreate() {
115 DCHECK(message_loop_->BelongsToCurrentThread()); 116 DCHECK(message_loop_->BelongsToCurrentThread());
116 117
117 // Close() can be called before DoCreate() is executed. 118 // Close() can be called before DoCreate() is executed.
118 if (state_ == kClosed) 119 if (state_ == kClosed)
119 return; 120 return;
120 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_; 121 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_;
121 122
122 DoStopCloseAndClearStream(NULL); 123 DoStopCloseAndClearStream(NULL);
123 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params_); 124 stream_ = diverting_to_stream_ ? diverting_to_stream_ :
125 audio_manager_->MakeAudioOutputStreamProxy(params_);
124 if (!stream_) { 126 if (!stream_) {
125 state_ = kError; 127 state_ = kError;
126 128
127 // TODO(hclam): Define error types. 129 // TODO(hclam): Define error types.
128 handler_->OnError(this, 0); 130 handler_->OnError(this, 0);
129 return; 131 return;
130 } 132 }
131 133
132 if (!stream_->Open()) { 134 if (!stream_->Open()) {
133 state_ = kError; 135 state_ = kError;
134 DoStopCloseAndClearStream(NULL); 136 DoStopCloseAndClearStream(NULL);
135 137
136 // TODO(hclam): Define error types. 138 // TODO(hclam): Define error types.
137 handler_->OnError(this, 0); 139 handler_->OnError(this, 0);
138 return; 140 return;
139 } 141 }
140 142
141 // Everything started okay, so register for state change callbacks if we have 143 // Everything started okay, so re-register for state change callbacks if
142 // not already done so. 144 // stream_ was created via AudioManager. Note: The call to
143 if (state_ != kRecreating) 145 // DoStopCloseAndClearStream() above called
146 // RemoveOutputDeviceChangeListener().
147 if (stream_ != diverting_to_stream_)
144 audio_manager_->AddOutputDeviceChangeListener(this); 148 audio_manager_->AddOutputDeviceChangeListener(this);
145 149
146 // We have successfully opened the stream. Set the initial volume. 150 // We have successfully opened the stream. Set the initial volume.
147 stream_->SetVolume(volume_); 151 stream_->SetVolume(volume_);
148 152
149 // Finally set the state to kCreated. 153 // Finally set the state to kCreated.
150 State original_state = state_; 154 State original_state = state_;
151 state_ = kCreated; 155 state_ = kCreated;
152 156
153 // And then report we have been created if we haven't done so already. 157 // 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. 345 // Handle error on the audio controller thread.
342 message_loop_->PostTask(FROM_HERE, base::Bind( 346 message_loop_->PostTask(FROM_HERE, base::Bind(
343 &AudioOutputController::DoReportError, this, code)); 347 &AudioOutputController::DoReportError, this, code));
344 } 348 }
345 349
346 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { 350 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) {
347 DCHECK(message_loop_->BelongsToCurrentThread()); 351 DCHECK(message_loop_->BelongsToCurrentThread());
348 352
349 // Allow calling unconditionally and bail if we don't have a stream_ to close. 353 // Allow calling unconditionally and bail if we don't have a stream_ to close.
350 if (stream_) { 354 if (stream_) {
355 // De-register from state change callbacks if stream_ was created via
356 // AudioManager.
357 if (stream_ != diverting_to_stream_)
358 audio_manager_->RemoveOutputDeviceChangeListener(this);
359
351 stream_->Stop(); 360 stream_->Stop();
352 stream_->Close(); 361 stream_->Close();
362 if (stream_ == diverting_to_stream_)
363 diverting_to_stream_ = NULL;
353 stream_ = NULL; 364 stream_ = NULL;
354 365
355 audio_manager_->RemoveOutputDeviceChangeListener(this);
356 audio_manager_ = NULL;
357
358 weak_this_.InvalidateWeakPtrs(); 366 weak_this_.InvalidateWeakPtrs();
359 } 367 }
360 368
361 // Should be last in the method, do not touch "this" from here on. 369 // Should be last in the method, do not touch "this" from here on.
362 if (done) 370 if (done)
363 done->Signal(); 371 done->Signal();
364 } 372 }
365 373
366 void AudioOutputController::OnDeviceChange() { 374 void AudioOutputController::OnDeviceChange() {
367 DCHECK(message_loop_->BelongsToCurrentThread()); 375 DCHECK(message_loop_->BelongsToCurrentThread());
368 376
369 // We should always have a stream by this point. 377 // Recreate the stream (DoCreate() will first shut down an existing stream).
370 CHECK(stream_); 378 // Exit if we ran into an error.
371 379 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; 380 state_ = kRecreating;
380 DoCreate(); 381 DoCreate();
381 if (!stream_ || state_ == kError) 382 if (!stream_ || state_ == kError)
382 return; 383 return;
383 384
384 // Get us back to the original state or an equivalent state. 385 // Get us back to the original state or an equivalent state.
385 switch (original_state) { 386 switch (original_state) {
386 case kStarting: 387 case kStarting:
387 case kPlaying: 388 case kPlaying:
388 DoPlay(); 389 DoPlay();
389 return; 390 return;
390 case kCreated: 391 case kCreated:
391 case kPausedWhenStarting: 392 case kPausedWhenStarting:
392 case kPaused: 393 case kPaused:
393 // From the outside these three states are equivalent. 394 // From the outside these three states are equivalent.
394 return; 395 return;
395 default: 396 default:
396 NOTREACHED() << "Invalid original state."; 397 NOTREACHED() << "Invalid original state.";
397 } 398 }
398 } 399 }
399 400
401 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
402 if (!message_loop_->BelongsToCurrentThread()) {
DaleCurtis 2013/01/02 21:56:44 This is still odd and inconsistent with the rest o
miu 2013/01/03 22:30:42 Done.
403 DCHECK(divert_thread_checker_.CalledOnValidThread());
404 message_loop_->PostTask(
405 FROM_HERE,
406 base::Bind(&AudioOutputController::StartDiverting, this, to_stream));
407 return;
408 }
409
410 DCHECK(!diverting_to_stream_);
411 diverting_to_stream_ = to_stream;
412 DCHECK_NE(kClosed, state_);
DaleCurtis 2013/01/02 21:56:44 Instead of a DHCECK_NE, shouldn't this be an if (s
miu 2013/01/03 22:30:42 Done.
413 OnDeviceChange();
414 }
415
416 void AudioOutputController::StopDiverting() {
DaleCurtis 2013/01/02 21:56:44 Ditto.
miu 2013/01/03 22:30:42 Done.
417 if (!message_loop_->BelongsToCurrentThread()) {
418 DCHECK(divert_thread_checker_.CalledOnValidThread());
419 message_loop_->PostTask(
420 FROM_HERE, base::Bind(&AudioOutputController::StopDiverting, this));
421 return;
422 }
423
424 if (state_ != kClosed) {
425 OnDeviceChange();
DaleCurtis 2013/01/02 21:56:44 This needs a comment since it's subtle that OnDevi
miu 2013/01/03 22:30:42 Done.
426 DCHECK(!diverting_to_stream_);
427 }
428 }
429
400 } // namespace media 430 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698