Index: media/audio/audio_output_device.cc |
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc |
index d09e32c4a77c6f2805a5bd95ee42023420339fc0..18fabdc51fb9cc3b8f04fa37abc029dd61b12ee7 100644 |
--- a/media/audio/audio_output_device.cc |
+++ b/media/audio/audio_output_device.cc |
@@ -46,21 +46,32 @@ AudioOutputDevice::AudioOutputDevice( |
: ScopedLoopObserver(io_loop), |
input_channels_(0), |
callback_(NULL), |
- ipc_(ipc), |
- stream_id_(0), |
+ stream_id_(-1), |
+ state_(kIpcClosed), |
play_on_start_(true), |
- is_started_(false), |
stopping_hack_(false) { |
- CHECK(ipc_); |
+ CHECK(ipc); |
+ message_loop()->PostTask(FROM_HERE, |
+ base::Bind(&AudioOutputDevice::RegisterDelegateOnIOThread, this, ipc)); |
} |
-void AudioOutputDevice::Initialize(const AudioParameters& params, |
- RenderCallback* callback) { |
- CHECK_EQ(0, stream_id_) << |
- "AudioOutputDevice::Initialize() must be called before Start()"; |
+void AudioOutputDevice::RegisterDelegateOnIOThread(AudioOutputIPC* ipc) { |
+ DCHECK(message_loop()->BelongsToCurrentThread()); |
+ DCHECK_EQ(kIpcClosed, state_); |
+ ipc_ = ipc->AsWeakPtr(); |
+ stream_id_ = ipc_ ? ipc_->AddDelegate(this) : 0; |
+ if (stream_id_ > 0) |
+ state_ = kIdle; |
+} |
- CHECK(!callback_); // Calling Initialize() twice? |
+int AudioOutputDevice::stream_id() const { |
+ DCHECK_LE(0, stream_id_) << "Call to stream_id() before being initialized."; |
+ return stream_id_; |
+} |
+void AudioOutputDevice::Initialize(const AudioParameters& params, |
+ RenderCallback* callback) { |
+ DCHECK(!callback_) << "Calling Initialize() twice?"; |
audio_parameters_ = params; |
callback_ = callback; |
} |
@@ -75,9 +86,8 @@ void AudioOutputDevice::InitializeIO(const AudioParameters& params, |
} |
AudioOutputDevice::~AudioOutputDevice() { |
- // The current design requires that the user calls Stop() before deleting |
- // this class. |
- CHECK_EQ(0, stream_id_); |
+ message_loop()->PostTask(FROM_HERE, |
+ base::Bind(&AudioOutputIPC::RemoveDelegate, ipc_, stream_id_)); |
} |
void AudioOutputDevice::Start() { |
@@ -123,49 +133,47 @@ bool AudioOutputDevice::SetVolume(double volume) { |
void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params, |
int input_channels) { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
- // Make sure we don't create the stream more than once. |
- DCHECK_EQ(0, stream_id_); |
- if (stream_id_) |
- return; |
- |
- stream_id_ = ipc_->AddDelegate(this); |
- ipc_->CreateStream(stream_id_, params, input_channels); |
+ if (state_ == kIdle && ipc_) { |
+ state_ = kCreatingStream; |
+ ipc_->CreateStream(stream_id_, params, input_channels); |
+ } |
} |
void AudioOutputDevice::PlayOnIOThread() { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
- if (stream_id_ && is_started_) |
+ if (state_ == kPaused && ipc_) { |
ipc_->PlayStream(stream_id_); |
- else |
+ state_ = kPlaying; |
+ play_on_start_ = false; |
+ } else { |
play_on_start_ = true; |
+ } |
} |
void AudioOutputDevice::PauseOnIOThread(bool flush) { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
- if (stream_id_ && is_started_) { |
- ipc_->PauseStream(stream_id_); |
- if (flush) |
- ipc_->FlushStream(stream_id_); |
+ if (state_ == kPlaying) { |
+ if (ipc_) { |
+ ipc_->PauseStream(stream_id_); |
+ if (flush) |
+ ipc_->FlushStream(stream_id_); |
+ } |
+ state_ = kPaused; |
} else { |
// Note that |flush| isn't relevant here since this is the case where |
// the stream is first starting. |
- play_on_start_ = false; |
} |
+ play_on_start_ = false; |
} |
void AudioOutputDevice::ShutDownOnIOThread() { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
// Make sure we don't call shutdown more than once. |
- if (stream_id_) { |
- is_started_ = false; |
- |
- if (ipc_) { |
+ if (state_ >= kCreatingStream) { |
+ if (ipc_) |
ipc_->CloseStream(stream_id_); |
- ipc_->RemoveDelegate(stream_id_); |
- } |
- |
- stream_id_ = 0; |
+ state_ = kIdle; |
} |
// We can run into an issue where ShutDownOnIOThread is called right after |
@@ -185,7 +193,7 @@ void AudioOutputDevice::ShutDownOnIOThread() { |
void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
- if (stream_id_) |
+ if (state_ >= kPaused && ipc_) |
ipc_->SetVolume(stream_id_, volume); |
} |
@@ -193,7 +201,7 @@ void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { |
DCHECK(message_loop()->BelongsToCurrentThread()); |
// Do nothing if the stream has been closed. |
- if (!stream_id_) |
+ if (state_ < kCreatingStream) |
return; |
if (state == AudioOutputIPCDelegate::kError) { |
@@ -222,12 +230,8 @@ void AudioOutputDevice::OnStreamCreated( |
DCHECK_GE(socket_handle, 0); |
#endif |
- // We should only get this callback if stream_id_ is valid. If it is not, |
- // the IPC layer should have closed the shared memory and socket handles |
- // for us and not invoked the callback. The basic assertion is that when |
- // stream_id_ is 0 the AudioOutputDevice instance is not registered as a |
- // delegate and hence it should not receive callbacks. |
- DCHECK(stream_id_); |
+ if (state_ != kCreatingStream) |
+ return; |
// We can receive OnStreamCreated() on the IO thread after the client has |
// called Stop() but before ShutDownOnIOThread() is processed. In such a |
@@ -250,16 +254,18 @@ void AudioOutputDevice::OnStreamCreated( |
audio_parameters_, input_channels_, handle, length, callback_)); |
audio_thread_.Start(audio_callback_.get(), socket_handle, |
"AudioOutputDevice"); |
+ state_ = kPaused; |
// We handle the case where Play() and/or Pause() may have been called |
// multiple times before OnStreamCreated() gets called. |
- is_started_ = true; |
if (play_on_start_) |
PlayOnIOThread(); |
} |
void AudioOutputDevice::OnIPCClosed() { |
- ipc_ = NULL; |
+ DCHECK(message_loop()->BelongsToCurrentThread()); |
+ state_ = kIpcClosed; |
+ ipc_.reset(); |
} |
void AudioOutputDevice::WillDestroyCurrentMessageLoop() { |