summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 09:16:58 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 09:16:58 +0000
commit8f5fc718853a128dc2f70ec4e55db4044af64bcc (patch)
tree4f283d47012fd9594433990e89ad7f4fff3f0bcd
parentae4e03118d9a8792b907c923adf6516495f20536 (diff)
downloadchromium_src-8f5fc718853a128dc2f70ec4e55db4044af64bcc.zip
chromium_src-8f5fc718853a128dc2f70ec4e55db4044af64bcc.tar.gz
chromium_src-8f5fc718853a128dc2f70ec4e55db4044af64bcc.tar.bz2
Add thread safety to AudioManagerBase to protect access to the audio thread member variable.
This is is a tentative fix for an issue where the AudioManager can crash while tearing down the audio thread. I suspect that this happens because more than one cleanup attempts were made since the class wasn't thread safe. I'm also changing direct access to the thread's MessageLoop* to use MessageLoopProxy based on the same theory. BUG=110051 TEST=Run media tests. Review URL: https://chromiumcodereview.appspot.com/9255017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118272 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/test/webrtc_audio_device_test.cc8
-rw-r--r--content/test/webrtc_audio_device_test.h4
-rw-r--r--media/audio/audio_low_latency_input_output_unittest.cc7
-rw-r--r--media/audio/audio_manager.h5
-rw-r--r--media/audio/audio_manager_base.cc61
-rw-r--r--media/audio/audio_manager_base.h18
-rw-r--r--media/audio/audio_output_controller.cc29
-rw-r--r--media/audio/audio_output_controller.h2
-rw-r--r--media/audio/audio_output_dispatcher.cc10
-rw-r--r--media/audio/audio_output_dispatcher.h2
-rw-r--r--media/audio/audio_output_proxy.cc17
-rw-r--r--media/audio/audio_output_proxy.h7
-rw-r--r--media/audio/audio_output_proxy_unittest.cc5
-rw-r--r--media/audio/linux/alsa_output.cc30
-rw-r--r--media/audio/linux/alsa_output_unittest.cc6
-rw-r--r--media/audio/linux/audio_manager_linux.cc17
16 files changed, 125 insertions, 103 deletions
diff --git a/content/test/webrtc_audio_device_test.cc b/content/test/webrtc_audio_device_test.cc
index d4ea8b7..94c155b 100644
--- a/content/test/webrtc_audio_device_test.cc
+++ b/content/test/webrtc_audio_device_test.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -277,7 +277,8 @@ bool WebRTCAudioDeviceTest::OnMessageReceived(const IPC::Message& message) {
// Posts a final task to the IO message loop and waits for completion.
void WebRTCAudioDeviceTest::WaitForIOThreadCompletion() {
- WaitForMessageLoopCompletion(ChildProcess::current()->io_message_loop());
+ WaitForMessageLoopCompletion(
+ ChildProcess::current()->io_message_loop()->message_loop_proxy());
}
void WebRTCAudioDeviceTest::WaitForAudioManagerCompletion() {
@@ -285,7 +286,8 @@ void WebRTCAudioDeviceTest::WaitForAudioManagerCompletion() {
WaitForMessageLoopCompletion(audio_manager_->GetMessageLoop());
}
-void WebRTCAudioDeviceTest::WaitForMessageLoopCompletion(MessageLoop* loop) {
+void WebRTCAudioDeviceTest::WaitForMessageLoopCompletion(
+ base::MessageLoopProxy* loop) {
base::WaitableEvent* event = new base::WaitableEvent(false, false);
loop->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
base::Unretained(event)));
diff --git a/content/test/webrtc_audio_device_test.h b/content/test/webrtc_audio_device_test.h
index d1caead..f821ad6 100644
--- a/content/test/webrtc_audio_device_test.h
+++ b/content/test/webrtc_audio_device_test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -144,7 +144,7 @@ class WebRTCAudioDeviceTest
// Posts a final task to the IO message loop and waits for completion.
void WaitForIOThreadCompletion();
void WaitForAudioManagerCompletion();
- void WaitForMessageLoopCompletion(MessageLoop* loop);
+ void WaitForMessageLoopCompletion(base::MessageLoopProxy* loop);
// Convenience getter for gmock.
MockMediaObserver& media_observer() const {
diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc
index 683bf2b..a989a4e 100644
--- a/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/media/audio/audio_low_latency_input_output_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include "base/environment.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/synchronization/lock.h"
#include "base/test/test_timeouts.h"
@@ -82,8 +83,8 @@ class MockAudioManager : public AudioManagerAnyPlatform {
virtual ~MockAudioManager() {}
- virtual MessageLoop* GetMessageLoop() OVERRIDE {
- return MessageLoop::current();
+ virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE {
+ return MessageLoop::current()->message_loop_proxy();
}
private:
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h
index fd59486..b1ca217 100644
--- a/media/audio/audio_manager.h
+++ b/media/audio/audio_manager.h
@@ -16,6 +16,9 @@
class AudioInputStream;
class AudioOutputStream;
class MessageLoop;
+namespace base {
+class MessageLoopProxy;
+}
// Manages all audio resources. In particular it owns the AudioOutputStream
// objects. Provides some convenience functions that avoid the need to provide
@@ -121,7 +124,7 @@ class MEDIA_EXPORT AudioManager
virtual bool IsRecordingInProcess() = 0;
// Returns message loop used for audio IO.
- virtual MessageLoop* GetMessageLoop() = 0;
+ virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() = 0;
protected:
// Called from Create() to initialize the instance.
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
index 696dd86..9202e58 100644
--- a/media/audio/audio_manager_base.cc
+++ b/media/audio/audio_manager_base.cc
@@ -5,6 +5,8 @@
#include "media/audio/audio_manager_base.h"
#include "base/bind.h"
+#include "base/message_loop_proxy.h"
+#include "base/threading/thread.h"
#include "media/audio/audio_output_dispatcher.h"
#include "media/audio/audio_output_proxy.h"
@@ -14,8 +16,7 @@ const char AudioManagerBase::kDefaultDeviceName[] = "Default";
const char AudioManagerBase::kDefaultDeviceId[] = "default";
AudioManagerBase::AudioManagerBase()
- : audio_thread_("AudioThread"),
- num_active_input_streams_(0) {
+ : num_active_input_streams_(0) {
}
AudioManagerBase::~AudioManagerBase() {
@@ -24,36 +25,45 @@ AudioManagerBase::~AudioManagerBase() {
#ifndef NDEBUG
void AudioManagerBase::AddRef() const {
- const MessageLoop* loop = audio_thread_.message_loop();
- DCHECK(loop == NULL || loop != MessageLoop::current());
+ {
+ base::AutoLock lock(audio_thread_lock_);
+ const MessageLoop* loop = audio_thread_.get() ?
+ audio_thread_->message_loop() : NULL;
+ DCHECK(loop == NULL || loop != MessageLoop::current());
+ }
AudioManager::AddRef();
}
void AudioManagerBase::Release() const {
- const MessageLoop* loop = audio_thread_.message_loop();
- DCHECK(loop == NULL || loop != MessageLoop::current());
+ {
+ base::AutoLock lock(audio_thread_lock_);
+ const MessageLoop* loop = audio_thread_.get() ?
+ audio_thread_->message_loop() : NULL;
+ DCHECK(loop == NULL || loop != MessageLoop::current());
+ }
AudioManager::Release();
}
#endif
void AudioManagerBase::Init() {
- CHECK(audio_thread_.Start());
+ base::AutoLock lock(audio_thread_lock_);
+ DCHECK(!audio_thread_.get());
+ audio_thread_.reset(new base::Thread("AudioThread"));
+ CHECK(audio_thread_->Start());
}
string16 AudioManagerBase::GetAudioInputDeviceModel() {
return string16();
}
-MessageLoop* AudioManagerBase::GetMessageLoop() {
- return audio_thread_.message_loop();
+scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() {
+ base::AutoLock lock(audio_thread_lock_);
+ return audio_thread_.get() ? audio_thread_->message_loop_proxy() : NULL;
}
AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
const AudioParameters& params) {
- DCHECK_EQ(MessageLoop::current(), GetMessageLoop());
-
- if (!initialized())
- return NULL;
+ DCHECK(GetMessageLoop()->BelongsToCurrentThread());
scoped_refptr<AudioOutputDispatcher>& dispatcher =
output_dispatchers_[params];
@@ -88,23 +98,34 @@ bool AudioManagerBase::IsRecordingInProcess() {
}
void AudioManagerBase::Shutdown() {
- if (!initialized())
- return;
+ // To avoid running into deadlocks while we stop the thread, shut it down
+ // via a local variable while not holding the audio thread lock.
+ scoped_ptr<base::Thread> audio_thread;
+ {
+ base::AutoLock lock(audio_thread_lock_);
+ audio_thread_.swap(audio_thread);
+ }
- DCHECK_NE(MessageLoop::current(), GetMessageLoop());
+ if (!audio_thread.get())
+ return;
+
+ CHECK_NE(MessageLoop::current(), audio_thread->message_loop());
// We must use base::Unretained since Shutdown might have been called from
// the destructor and we can't alter the refcount of the object at that point.
- GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
+ audio_thread->message_loop()->PostTask(FROM_HERE, base::Bind(
&AudioManagerBase::ShutdownOnAudioThread,
base::Unretained(this)));
+
// Stop() will wait for any posted messages to be processed first.
- audio_thread_.Stop();
+ audio_thread->Stop();
}
void AudioManagerBase::ShutdownOnAudioThread() {
- DCHECK_EQ(MessageLoop::current(), GetMessageLoop());
-
+ // This should always be running on the audio thread, but since we've cleared
+ // the audio_thread_ member pointer when we get here, we can't verify exactly
+ // what thread we're running on. The method is not public though and only
+ // called from one place, so we'll leave it at that.
AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin();
for (; it != output_dispatchers_.end(); ++it) {
scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second;
diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h
index 15e18be..1cba8a8 100644
--- a/media/audio/audio_manager_base.h
+++ b/media/audio/audio_manager_base.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,11 +9,16 @@
#include "base/atomic_ref_count.h"
#include "base/compiler_specific.h"
-#include "base/threading/thread.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
#include "media/audio/audio_manager.h"
class AudioOutputDispatcher;
+namespace base {
+class Thread;
+}
+
// AudioManagerBase provides AudioManager functions common for all platforms.
class MEDIA_EXPORT AudioManagerBase : public AudioManager {
public:
@@ -34,7 +39,7 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
virtual void Init() OVERRIDE;
- virtual MessageLoop* GetMessageLoop() OVERRIDE;
+ virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE;
virtual string16 GetAudioInputDeviceModel() OVERRIDE;
@@ -66,12 +71,13 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
void ShutdownOnAudioThread();
- bool initialized() { return audio_thread_.IsRunning(); }
-
// Thread used to interact with AudioOutputStreams created by this
// audio manger.
- base::Thread audio_thread_;
+ scoped_ptr<base::Thread> audio_thread_;
+ mutable base::Lock audio_thread_lock_;
+ // Map of cached AudioOutputDispatcher instances. Must only be touched
+ // from the audio thread (no locking).
AudioOutputDispatchersMap output_dispatchers_;
// Counts the number of active input streams to find out if something else
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index 9f6d7da..d087a70 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -42,10 +42,11 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager,
AudioOutputController::~AudioOutputController() {
DCHECK_EQ(kClosed, state_);
- if (message_loop_ == MessageLoop::current()) {
+ DCHECK(message_loop_);
+
+ if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) {
DoStopCloseAndClearStream(NULL);
} else {
- DCHECK(message_loop_);
WaitableEvent completion(true /* manual reset */,
false /* initial state */);
message_loop_->PostTask(FROM_HERE,
@@ -145,7 +146,7 @@ void AudioOutputController::EnqueueData(const uint8* data, uint32 size) {
}
void AudioOutputController::DoCreate(const AudioParameters& params) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// Close() can be called before DoCreate() is executed.
if (state_ == kClosed)
@@ -185,7 +186,7 @@ void AudioOutputController::DoCreate(const AudioParameters& params) {
}
void AudioOutputController::DoPlay() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// We can start from created or paused state.
if (state_ != kCreated && state_ != kPaused)
@@ -204,14 +205,14 @@ void AudioOutputController::DoPlay() {
FROM_HERE,
base::Bind(&AudioOutputController::PollAndStartIfDataReady,
weak_this_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
+ kPollPauseInMilliseconds);
} else {
StartStream();
}
}
void AudioOutputController::PollAndStartIfDataReady() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// Being paranoid: do nothing if state unexpectedly changed.
if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
@@ -232,12 +233,12 @@ void AudioOutputController::PollAndStartIfDataReady() {
FROM_HERE,
base::Bind(&AudioOutputController::PollAndStartIfDataReady,
weak_this_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
+ kPollPauseInMilliseconds);
}
}
void AudioOutputController::StartStream() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
state_ = kPlaying;
// We start the AudioOutputStream lazily.
@@ -248,7 +249,7 @@ void AudioOutputController::StartStream() {
}
void AudioOutputController::DoPause() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
if (stream_)
stream_->Stop();
@@ -282,7 +283,7 @@ void AudioOutputController::DoPause() {
}
void AudioOutputController::DoFlush() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// TODO(hclam): Actually flush the audio device.
@@ -296,7 +297,7 @@ void AudioOutputController::DoFlush() {
}
void AudioOutputController::DoClose(const base::Closure& closed_task) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
if (state_ != kClosed) {
DoStopCloseAndClearStream(NULL);
@@ -312,7 +313,7 @@ void AudioOutputController::DoClose(const base::Closure& closed_task) {
}
void AudioOutputController::DoSetVolume(double volume) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// 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.
@@ -332,7 +333,7 @@ void AudioOutputController::DoSetVolume(double volume) {
}
void AudioOutputController::DoReportError(int code) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
if (state_ != kClosed)
handler_->OnError(this, code);
}
@@ -415,7 +416,7 @@ void AudioOutputController::SubmitOnMoreData_Locked() {
}
void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK(message_loop_->BelongsToCurrentThread());
// Allow calling unconditionally and bail if we don't have a stream_ to close.
if (stream_ != NULL) {
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 24de175..f6e5722 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -254,7 +254,7 @@ class MEDIA_EXPORT AudioOutputController
SyncReader* sync_reader_;
// The message loop of audio thread that this object runs on.
- MessageLoop* message_loop_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
// When starting stream we wait for data to become available.
// Number of times left.
diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc
index 8e40277..b1f265b 100644
--- a/media/audio/audio_output_dispatcher.cc
+++ b/media/audio/audio_output_dispatcher.cc
@@ -14,7 +14,7 @@ AudioOutputDispatcher::AudioOutputDispatcher(
AudioManager* audio_manager, const AudioParameters& params,
base::TimeDelta close_delay)
: audio_manager_(audio_manager),
- message_loop_(audio_manager->GetMessageLoop()),
+ message_loop_(MessageLoop::current()),
params_(params),
pause_delay_(base::TimeDelta::FromMilliseconds(
2 * params.samples_per_packet *
@@ -25,7 +25,9 @@ AudioOutputDispatcher::AudioOutputDispatcher(
close_delay,
weak_this_.GetWeakPtr(),
&AudioOutputDispatcher::ClosePendingStreams) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
+ // We expect to be instantiated on the audio thread. Otherwise the
+ // message_loop_ member will point to the wrong message loop!
+ DCHECK(audio_manager->GetMessageLoop()->BelongsToCurrentThread());
}
AudioOutputDispatcher::~AudioOutputDispatcher() {
@@ -133,10 +135,6 @@ void AudioOutputDispatcher::Shutdown() {
pausing_streams_.clear();
}
-MessageLoop* AudioOutputDispatcher::message_loop() {
- return message_loop_;
-}
-
bool AudioOutputDispatcher::CreateAndOpenStream() {
AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
if (!stream)
diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h
index 08e6893..cf01a31 100644
--- a/media/audio/audio_output_dispatcher.h
+++ b/media/audio/audio_output_dispatcher.h
@@ -69,8 +69,6 @@ class MEDIA_EXPORT AudioOutputDispatcher
// Called on the audio thread when the AudioManager is shutting down.
void Shutdown();
- MessageLoop* message_loop();
-
private:
friend class AudioOutputProxyTest;
diff --git a/media/audio/audio_output_proxy.cc b/media/audio/audio_output_proxy.cc
index e8309cf..29490db 100644
--- a/media/audio/audio_output_proxy.cc
+++ b/media/audio/audio_output_proxy.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,17 +14,16 @@ AudioOutputProxy::AudioOutputProxy(AudioOutputDispatcher* dispatcher)
state_(kCreated),
physical_stream_(NULL),
volume_(1.0) {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
}
AudioOutputProxy::~AudioOutputProxy() {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
DCHECK(state_ == kCreated || state_ == kClosed);
DCHECK(!physical_stream_);
}
bool AudioOutputProxy::Open() {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(state_, kCreated);
if (!dispatcher_->StreamOpened()) {
@@ -37,7 +36,7 @@ bool AudioOutputProxy::Open() {
}
void AudioOutputProxy::Start(AudioSourceCallback* callback) {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
DCHECK(physical_stream_ == NULL);
DCHECK_EQ(state_, kOpened);
@@ -54,7 +53,7 @@ void AudioOutputProxy::Start(AudioSourceCallback* callback) {
}
void AudioOutputProxy::Stop() {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
if (state_ != kPlaying)
return;
@@ -66,7 +65,7 @@ void AudioOutputProxy::Stop() {
}
void AudioOutputProxy::SetVolume(double volume) {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
volume_ = volume;
if (physical_stream_) {
physical_stream_->SetVolume(volume);
@@ -74,12 +73,12 @@ void AudioOutputProxy::SetVolume(double volume) {
}
void AudioOutputProxy::GetVolume(double* volume) {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
*volume = volume_;
}
void AudioOutputProxy::Close() {
- DCHECK_EQ(MessageLoop::current(), dispatcher_->message_loop());
+ DCHECK(CalledOnValidThread());
DCHECK(state_ == kCreated || state_ == kError || state_ == kOpened);
DCHECK(!physical_stream_);
diff --git a/media/audio/audio_output_proxy.h b/media/audio/audio_output_proxy.h
index af081c1..8e1b350 100644
--- a/media/audio/audio_output_proxy.h
+++ b/media/audio/audio_output_proxy.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
@@ -21,7 +22,9 @@ class AudioOutputDispatcher;
//
// AudioOutputProxy uses AudioOutputDispatcher to open and close
// physical output streams.
-class MEDIA_EXPORT AudioOutputProxy : public AudioOutputStream {
+class MEDIA_EXPORT AudioOutputProxy
+ : public AudioOutputStream,
+ public NON_EXPORTED_BASE(base::NonThreadSafe) {
public:
// Caller keeps ownership of |dispatcher|.
explicit AudioOutputProxy(AudioOutputDispatcher* dispatcher);
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc
index b2ff1a9..957e77a 100644
--- a/media/audio/audio_output_proxy_unittest.cc
+++ b/media/audio/audio_output_proxy_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#include "base/threading/platform_thread.h"
#include "media/audio/audio_output_dispatcher.h"
#include "media/audio/audio_output_proxy.h"
@@ -50,7 +51,7 @@ class MockAudioManager : public AudioManager {
MOCK_METHOD0(UnMuteAll, void());
MOCK_METHOD0(CanShowAudioInputSettings, bool());
MOCK_METHOD0(ShowAudioInputSettings, void());
- MOCK_METHOD0(GetMessageLoop, MessageLoop*());
+ MOCK_METHOD0(GetMessageLoop, scoped_refptr<base::MessageLoopProxy>());
MOCK_METHOD1(GetAudioInputDeviceNames, void(
media::AudioDeviceNames* device_name));
MOCK_METHOD0(IsRecordingInProcess, bool());
@@ -69,7 +70,7 @@ class AudioOutputProxyTest : public testing::Test {
virtual void SetUp() {
MockAudioManager* manager = new MockAudioManager();
EXPECT_CALL(*manager, GetMessageLoop())
- .WillRepeatedly(Return(&message_loop_));
+ .WillRepeatedly(Return(message_loop_.message_loop_proxy()));
manager_ = manager;
InitDispatcher(base::TimeDelta::FromMilliseconds(kTestCloseDelayMs));
}
diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc
index ef872c0..b3f931d 100644
--- a/media/audio/linux/alsa_output.cc
+++ b/media/audio/linux/alsa_output.cc
@@ -206,7 +206,7 @@ AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
state_(kCreated),
volume_(1.0f),
source_callback_(NULL) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
// Sanity check input values.
if ((params.sample_rate > kAlsaMaxSampleRate) || (params.sample_rate <= 0)) {
@@ -235,7 +235,7 @@ AlsaPcmOutputStream::~AlsaPcmOutputStream() {
}
bool AlsaPcmOutputStream::Open() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
if (state() == kInError)
return false;
@@ -293,7 +293,7 @@ bool AlsaPcmOutputStream::Open() {
}
void AlsaPcmOutputStream::Close() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
// Sanity check that the transition occurs correctly. It is safe to
// continue anyways because all operations for closing are idempotent.
@@ -322,7 +322,7 @@ void AlsaPcmOutputStream::Close() {
}
void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
CHECK(callback);
@@ -361,7 +361,7 @@ void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
}
void AlsaPcmOutputStream::Stop() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
// Reset the callback, so that it is not called anymore.
set_source_callback(NULL);
@@ -370,19 +370,19 @@ void AlsaPcmOutputStream::Stop() {
}
void AlsaPcmOutputStream::SetVolume(double volume) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
volume_ = static_cast<float>(volume);
}
void AlsaPcmOutputStream::GetVolume(double* volume) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
*volume = volume_;
}
void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
// If stopped, simulate a 0-length packet.
if (stop_stream_) {
@@ -473,7 +473,7 @@ void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
}
void AlsaPcmOutputStream::WritePacket() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
// If the device is in error, just eat the bytes.
if (stop_stream_) {
@@ -537,7 +537,7 @@ void AlsaPcmOutputStream::WritePacket() {
}
void AlsaPcmOutputStream::WriteTask() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
if (stop_stream_)
return;
@@ -553,7 +553,7 @@ void AlsaPcmOutputStream::WriteTask() {
}
void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
if (stop_stream_)
return;
@@ -607,7 +607,7 @@ void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE,
base::Bind(&AlsaPcmOutputStream::WriteTask,
weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(next_fill_time_ms));
+ next_fill_time_ms);
}
}
}
@@ -695,7 +695,7 @@ snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {
}
snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
if (stop_stream_)
return 0;
@@ -809,7 +809,7 @@ bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {
AlsaPcmOutputStream::InternalState
AlsaPcmOutputStream::TransitionTo(InternalState to) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
if (!CanTransitionTo(to)) {
NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to;
@@ -843,6 +843,6 @@ void AlsaPcmOutputStream::RunErrorCallback(int code) {
// Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
// release ownership of the currently registered callback.
void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
- DCHECK_EQ(MessageLoop::current(), manager_->GetMessageLoop());
+ DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread());
source_callback_ = callback;
}
diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/linux/alsa_output_unittest.cc
index 5b8405a..f1870d2 100644
--- a/media/audio/linux/alsa_output_unittest.cc
+++ b/media/audio/linux/alsa_output_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -88,8 +88,8 @@ class MockAudioManagerLinux : public AudioManagerLinux {
// We don't mock this method since all tests will do the same thing
// and use the current message loop.
- virtual MessageLoop* GetMessageLoop() {
- return MessageLoop::current();
+ virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE {
+ return MessageLoop::current()->message_loop_proxy();
}
};
diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc
index 6aaf591..da24f12 100644
--- a/media/audio/linux/audio_manager_linux.cc
+++ b/media/audio/linux/audio_manager_linux.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -49,17 +49,9 @@ bool AudioManagerLinux::HasAudioInputDevices() {
AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream(
const AudioParameters& params) {
- // Early return for testing hook. Do this before checking for
- // |initialized_|.
- if (params.format == AudioParameters::AUDIO_MOCK) {
+ // Early return for testing hook.
+ if (params.format == AudioParameters::AUDIO_MOCK)
return FakeAudioOutputStream::MakeFakeStream(params);
- }
-
- if (!initialized()) {
- // We should never get here since this method is called on the audio thread.
- NOTREACHED();
- return NULL;
- }
// Don't allow opening more than |kMaxOutputStreams| streams.
if (active_output_stream_count_ >= kMaxOutputStreams)
@@ -97,9 +89,6 @@ AudioInputStream* AudioManagerLinux::MakeAudioInputStream(
return FakeAudioInputStream::MakeFakeStream(params);
}
- if (!initialized())
- return NULL;
-
std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ?
AlsaPcmInputStream::kAutoSelectDevice : device_id;
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) {