| 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() {
|
|
|