Index: media/audio/audio_output_controller.cc |
=================================================================== |
--- media/audio/audio_output_controller.cc (revision 57255) |
+++ media/audio/audio_output_controller.cc (working copy) |
@@ -4,8 +4,6 @@ |
#include "media/audio/audio_output_controller.h" |
-#include "base/message_loop.h" |
- |
// The following parameters limit the request buffer and packet size from the |
// renderer to avoid renderer from requesting too much memory. |
static const uint32 kMegabytes = 1024 * 1024; |
@@ -37,12 +35,12 @@ |
uint32 capacity, |
SyncReader* sync_reader) |
: handler_(handler), |
- stream_(NULL), |
volume_(1.0), |
state_(kEmpty), |
hardware_pending_bytes_(0), |
buffer_capacity_(capacity), |
- sync_reader_(sync_reader) { |
+ sync_reader_(sync_reader), |
+ thread_("AudioOutputControllerThread") { |
} |
AudioOutputController::~AudioOutputController() { |
@@ -67,9 +65,10 @@ |
scoped_refptr<AudioOutputController> controller = new AudioOutputController( |
event_handler, buffer_capacity, NULL); |
- controller->message_loop_ = |
- AudioManager::GetAudioManager()->GetMessageLoop(); |
- controller->message_loop_->PostTask( |
+ // Start the audio controller thread and post a task to create the |
+ // audio stream. |
+ controller->thread_.Start(); |
+ controller->thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, |
format, channels, sample_rate, bits_per_sample, |
@@ -97,9 +96,10 @@ |
scoped_refptr<AudioOutputController> controller = new AudioOutputController( |
event_handler, 0, sync_reader); |
- controller->message_loop_ = |
- AudioManager::GetAudioManager()->GetMessageLoop(); |
- controller->message_loop_->PostTask( |
+ // Start the audio controller thread and post a task to create the |
+ // audio stream. |
+ controller->thread_.Start(); |
+ controller->thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, |
format, channels, sample_rate, bits_per_sample, |
@@ -108,43 +108,43 @@ |
} |
void AudioOutputController::Play() { |
- DCHECK(message_loop_); |
- message_loop_->PostTask( |
+ DCHECK(thread_.IsRunning()); |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoPlay)); |
} |
void AudioOutputController::Pause() { |
- DCHECK(message_loop_); |
- message_loop_->PostTask( |
+ DCHECK(thread_.IsRunning()); |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoPause)); |
} |
void AudioOutputController::Flush() { |
- DCHECK(message_loop_); |
- message_loop_->PostTask( |
+ DCHECK(thread_.IsRunning()); |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoFlush)); |
} |
void AudioOutputController::Close() { |
- { |
- AutoLock auto_lock(lock_); |
- // Don't do anything if the stream is already closed. |
- if (state_ == kClosed) |
- return; |
- state_ = kClosed; |
+ if (!thread_.IsRunning()) { |
+ // If the thread is not running make sure we are stopped. |
+ DCHECK_EQ(kClosed, state_); |
+ return; |
} |
- message_loop_->PostTask( |
+ // Wait for all tasks to complete on the audio thread. |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoClose)); |
+ thread_.Stop(); |
} |
void AudioOutputController::SetVolume(double volume) { |
- DCHECK(message_loop_); |
- message_loop_->PostTask( |
+ DCHECK(thread_.IsRunning()); |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoSetVolume, volume)); |
} |
@@ -159,15 +159,9 @@ |
void AudioOutputController::DoCreate(AudioManager::Format format, int channels, |
int sample_rate, int bits_per_sample, |
uint32 hardware_buffer_size) { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
+ DCHECK_EQ(kEmpty, state_); |
- AutoLock auto_lock(lock_); |
- |
- // Close() can be called before DoCreate() is executed. |
- if (state_ == kClosed) |
- return; |
- DCHECK(state_ == kEmpty); |
- |
// Create the stream in the first place. |
stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream( |
format, channels, sample_rate, bits_per_sample); |
@@ -197,20 +191,22 @@ |
// If in normal latency mode then start buffering. |
if (!LowLatencyMode()) { |
+ AutoLock auto_lock(lock_); |
SubmitOnMoreData_Locked(); |
} |
} |
void AudioOutputController::DoPlay() { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
+ // We can start from created or paused state. |
+ if (state_ != kCreated && state_ != kPaused) |
+ return; |
+ |
State old_state; |
// Update the |state_| to kPlaying. |
{ |
AutoLock auto_lock(lock_); |
- // We can start from created or paused state. |
- if (state_ != kCreated && state_ != kPaused) |
- return; |
old_state = state_; |
state_ = kPlaying; |
} |
@@ -223,14 +219,15 @@ |
} |
void AudioOutputController::DoPause() { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
+ // We can pause from started state. |
+ if (state_ != kPlaying) |
+ return; |
+ |
// Sets the |state_| to kPaused so we don't draw more audio data. |
{ |
AutoLock auto_lock(lock_); |
- // We can pause from started state. |
- if (state_ != kPlaying) |
- return; |
state_ = kPaused; |
} |
@@ -243,22 +240,24 @@ |
} |
void AudioOutputController::DoFlush() { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
+ if (state_ != kPaused) |
+ return; |
+ |
// TODO(hclam): Actually flush the audio device. |
// If we are in the regular latency mode then flush the push source. |
if (!sync_reader_) { |
AutoLock auto_lock(lock_); |
- if (state_ != kPaused) |
- return; |
push_source_.ClearAll(); |
} |
} |
void AudioOutputController::DoClose() { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
- DCHECK_EQ(kClosed, state_); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
+ DCHECK_NE(kClosed, state_); |
+ |
// |stream_| can be null if creating the device failed in DoCreate(). |
if (stream_) { |
stream_->Stop(); |
@@ -266,26 +265,27 @@ |
// After stream is closed it is destroyed, so don't keep a reference to it. |
stream_ = NULL; |
} |
+ |
+ // Update the current state. Since the stream is closed at this point |
+ // there's no other threads reading |state_| so we don't need to lock. |
+ state_ = kClosed; |
} |
void AudioOutputController::DoSetVolume(double volume) { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
// Saves the volume to a member first. We may not be able to set the volume |
// right away but when the stream is created we'll set the volume. |
volume_ = volume; |
- { |
- AutoLock auto_lock(lock_); |
- if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) |
- return; |
- } |
+ if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) |
+ return; |
stream_->SetVolume(volume_); |
} |
void AudioOutputController::DoReportError(int code) { |
- DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); |
handler_->OnError(this, code); |
} |
@@ -332,7 +332,7 @@ |
void AudioOutputController::OnError(AudioOutputStream* stream, int code) { |
// Handle error on the audio controller thread. |
- message_loop_->PostTask( |
+ thread_.message_loop()->PostTask( |
FROM_HERE, |
NewRunnableMethod(this, &AudioOutputController::DoReportError, code)); |
} |