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

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: Minor tweaks and added some useful comments. 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 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 130
131 if (!stream_->Open()) { 131 if (!stream_->Open()) {
132 state_ = kError; 132 state_ = kError;
133 DoStopCloseAndClearStream(NULL); 133 DoStopCloseAndClearStream(NULL);
134 134
135 // TODO(hclam): Define error types. 135 // TODO(hclam): Define error types.
136 handler_->OnError(this, 0); 136 handler_->OnError(this, 0);
137 return; 137 return;
138 } 138 }
139 139
140 // Everything started okay, so register for state change callbacks if we have 140 // Everything started okay, so re-register for state change callbacks (the
141 // not already done so. 141 // call to DoStopCloseAndClearStream() above de-registered this instance).
142 if (state_ != kRecreating) 142 audio_manager_->AddOutputDeviceChangeListener(this);
143 audio_manager_->AddOutputDeviceChangeListener(this);
144 143
145 // We have successfully opened the stream. Set the initial volume. 144 // We have successfully opened the stream. Set the initial volume.
146 stream_->SetVolume(volume_); 145 stream_->SetVolume(volume_);
147 146
148 // Finally set the state to kCreated. 147 // Finally set the state to kCreated.
149 State original_state = state_; 148 State original_state = state_;
150 state_ = kCreated; 149 state_ = kCreated;
151 150
152 // And then report we have been created if we haven't done so already. 151 // And then report we have been created if we haven't done so already.
153 if (original_state != kRecreating) 152 if (original_state != kRecreating)
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 AudioBuffersState buffers_state) { 296 AudioBuffersState buffers_state) {
298 return OnMoreIOData(NULL, dest, buffers_state); 297 return OnMoreIOData(NULL, dest, buffers_state);
299 } 298 }
300 299
301 int AudioOutputController::OnMoreIOData(AudioBus* source, 300 int AudioOutputController::OnMoreIOData(AudioBus* source,
302 AudioBus* dest, 301 AudioBus* dest,
303 AudioBuffersState buffers_state) { 302 AudioBuffersState buffers_state) {
304 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 303 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
305 304
306 { 305 {
307 // Check state and do nothing if we are not playing. 306 // Check state. When not playing, fill the destination with zeros.
308 // We are on the hardware audio thread, so lock is needed. 307 // We are on the hardware audio thread, so lock is needed.
309 base::AutoLock auto_lock(lock_); 308 base::AutoLock auto_lock(lock_);
310 if (state_ != kPlaying) { 309 if (state_ != kPlaying) {
311 return 0; 310 dest->Zero();
311 return dest->frames();
312 } 312 }
313 } 313 }
314 314
315 int frames = sync_reader_->Read(source, dest); 315 int frames = sync_reader_->Read(source, dest);
316 sync_reader_->UpdatePendingBytes( 316 sync_reader_->UpdatePendingBytes(
317 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 317 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
318 return frames; 318 return frames;
319 } 319 }
320 320
321 void AudioOutputController::WaitTillDataReady() { 321 void AudioOutputController::WaitTillDataReady() {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 } 354 }
355 355
356 // Should be last in the method, do not touch "this" from here on. 356 // Should be last in the method, do not touch "this" from here on.
357 if (done) 357 if (done)
358 done->Signal(); 358 done->Signal();
359 } 359 }
360 360
361 void AudioOutputController::OnDeviceChange() { 361 void AudioOutputController::OnDeviceChange() {
362 DCHECK(message_loop_->BelongsToCurrentThread()); 362 DCHECK(message_loop_->BelongsToCurrentThread());
363 363
364 // We should always have a stream by this point. 364 // Preserve the original state.
365 CHECK(stream_); 365 State original_state = state_;
366 366
367 // Preserve the original state and shutdown the stream. 367 // Recreate the stream (DoCreate() will first shut down an existing stream).
368 State original_state = state_; 368 // Exit if we ran into an error.
369 stream_->Stop();
370 stream_->Close();
371 stream_ = NULL;
372
373 // Recreate the stream, exit if we ran into an error.
374 state_ = kRecreating; 369 state_ = kRecreating;
375 DoCreate(); 370 DoCreate();
376 if (!stream_ || state_ == kError) 371 if (!stream_ || state_ == kError)
377 return; 372 return;
378 373
379 // Get us back to the original state or an equivalent state. 374 // Get us back to the original state or an equivalent state.
380 switch (original_state) { 375 switch (original_state) {
381 case kStarting: 376 case kStarting:
382 case kPlaying: 377 case kPlaying:
383 DoPlay(); 378 DoPlay();
384 return; 379 return;
385 case kCreated: 380 case kCreated:
386 case kPausedWhenStarting: 381 case kPausedWhenStarting:
387 case kPaused: 382 case kPaused:
388 // From the outside these three states are equivalent. 383 // From the outside these three states are equivalent.
389 return; 384 return;
390 default: 385 default:
391 NOTREACHED() << "Invalid original state."; 386 NOTREACHED() << "Invalid original state.";
392 } 387 }
393 } 388 }
394 389
390 AudioOutputStream::AudioSourceCallback* AudioOutputController::Divert() {
391 // Assumption: AudioRendererHost is calling this method on the IO
392 // BrowserThread.
393 DCHECK(!message_loop_->BelongsToCurrentThread());
394
395 // Block until stream closure is complete because, otherwise, it's possible
396 // for two entities to be pulling audio data at the same time. In addition,
397 // a side effect of closing the stream is that this controller will be
398 // de-registered from device change events (from AudioManager) during the
399 // "divert."
400 base::WaitableEvent blocker(true, false);
401 message_loop_->PostTask(
402 FROM_HERE,
403 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, this,
404 &blocker));
405 blocker.Wait();
406
407 return this;
408 }
409
410 void AudioOutputController::Revert(
411 AudioOutputStream::AudioSourceCallback* asc) {
412 // Assumption: AudioRendererHost is calling this method on the IO
413 // BrowserThread.
414 DCHECK(!message_loop_->BelongsToCurrentThread());
415
416 DCHECK_EQ(this, asc);
417
418 // The following re-creates the normal audio output stream and places it in
419 // the correct playback state. It also re-registers this controller for
420 // device change events from AudioManager.
421 message_loop_->PostTask(
422 FROM_HERE, base::Bind(&AudioOutputController::OnDeviceChange, this));
423 }
424
395 } // namespace media 425 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698