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

Side by Side Diff: media/audio/audio_manager_base.cc

Issue 9255017: Add thread safety to AudioManagerBase to protect access to the audio thread member variable. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix style issue Created 8 years, 11 months 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
« no previous file with comments | « media/audio/audio_manager_base.h ('k') | media/audio/audio_output_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_manager_base.h" 5 #include "media/audio/audio_manager_base.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop_proxy.h"
9 #include "base/threading/thread.h"
8 #include "media/audio/audio_output_dispatcher.h" 10 #include "media/audio/audio_output_dispatcher.h"
9 #include "media/audio/audio_output_proxy.h" 11 #include "media/audio/audio_output_proxy.h"
10 12
11 static const int kStreamCloseDelaySeconds = 5; 13 static const int kStreamCloseDelaySeconds = 5;
12 14
13 const char AudioManagerBase::kDefaultDeviceName[] = "Default"; 15 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
14 const char AudioManagerBase::kDefaultDeviceId[] = "default"; 16 const char AudioManagerBase::kDefaultDeviceId[] = "default";
15 17
16 AudioManagerBase::AudioManagerBase() 18 AudioManagerBase::AudioManagerBase()
17 : audio_thread_("AudioThread"), 19 : num_active_input_streams_(0) {
18 num_active_input_streams_(0) {
19 } 20 }
20 21
21 AudioManagerBase::~AudioManagerBase() { 22 AudioManagerBase::~AudioManagerBase() {
22 Shutdown(); 23 Shutdown();
23 } 24 }
24 25
25 #ifndef NDEBUG 26 #ifndef NDEBUG
26 void AudioManagerBase::AddRef() const { 27 void AudioManagerBase::AddRef() const {
27 const MessageLoop* loop = audio_thread_.message_loop(); 28 {
28 DCHECK(loop == NULL || loop != MessageLoop::current()); 29 base::AutoLock lock(audio_thread_lock_);
30 const MessageLoop* loop = audio_thread_.get() ?
31 audio_thread_->message_loop() : NULL;
32 DCHECK(loop == NULL || loop != MessageLoop::current());
33 }
29 AudioManager::AddRef(); 34 AudioManager::AddRef();
30 } 35 }
31 36
32 void AudioManagerBase::Release() const { 37 void AudioManagerBase::Release() const {
33 const MessageLoop* loop = audio_thread_.message_loop(); 38 {
34 DCHECK(loop == NULL || loop != MessageLoop::current()); 39 base::AutoLock lock(audio_thread_lock_);
40 const MessageLoop* loop = audio_thread_.get() ?
41 audio_thread_->message_loop() : NULL;
42 DCHECK(loop == NULL || loop != MessageLoop::current());
43 }
35 AudioManager::Release(); 44 AudioManager::Release();
36 } 45 }
37 #endif 46 #endif
38 47
39 void AudioManagerBase::Init() { 48 void AudioManagerBase::Init() {
40 CHECK(audio_thread_.Start()); 49 base::AutoLock lock(audio_thread_lock_);
50 DCHECK(!audio_thread_.get());
51 audio_thread_.reset(new base::Thread("AudioThread"));
52 CHECK(audio_thread_->Start());
41 } 53 }
42 54
43 string16 AudioManagerBase::GetAudioInputDeviceModel() { 55 string16 AudioManagerBase::GetAudioInputDeviceModel() {
44 return string16(); 56 return string16();
45 } 57 }
46 58
47 MessageLoop* AudioManagerBase::GetMessageLoop() { 59 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() {
48 return audio_thread_.message_loop(); 60 base::AutoLock lock(audio_thread_lock_);
61 return audio_thread_.get() ? audio_thread_->message_loop_proxy() : NULL;
49 } 62 }
50 63
51 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( 64 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
52 const AudioParameters& params) { 65 const AudioParameters& params) {
53 DCHECK_EQ(MessageLoop::current(), GetMessageLoop()); 66 DCHECK(GetMessageLoop()->BelongsToCurrentThread());
54
55 if (!initialized())
56 return NULL;
57 67
58 scoped_refptr<AudioOutputDispatcher>& dispatcher = 68 scoped_refptr<AudioOutputDispatcher>& dispatcher =
59 output_dispatchers_[params]; 69 output_dispatchers_[params];
60 if (!dispatcher) 70 if (!dispatcher)
61 dispatcher = new AudioOutputDispatcher( 71 dispatcher = new AudioOutputDispatcher(
62 this, params, base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds)); 72 this, params, base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds));
63 return new AudioOutputProxy(dispatcher); 73 return new AudioOutputProxy(dispatcher);
64 } 74 }
65 75
66 bool AudioManagerBase::CanShowAudioInputSettings() { 76 bool AudioManagerBase::CanShowAudioInputSettings() {
(...skipping 14 matching lines...) Expand all
81 void AudioManagerBase::DecreaseActiveInputStreamCount() { 91 void AudioManagerBase::DecreaseActiveInputStreamCount() {
82 DCHECK(IsRecordingInProcess()); 92 DCHECK(IsRecordingInProcess());
83 base::AtomicRefCountDec(&num_active_input_streams_); 93 base::AtomicRefCountDec(&num_active_input_streams_);
84 } 94 }
85 95
86 bool AudioManagerBase::IsRecordingInProcess() { 96 bool AudioManagerBase::IsRecordingInProcess() {
87 return !base::AtomicRefCountIsZero(&num_active_input_streams_); 97 return !base::AtomicRefCountIsZero(&num_active_input_streams_);
88 } 98 }
89 99
90 void AudioManagerBase::Shutdown() { 100 void AudioManagerBase::Shutdown() {
91 if (!initialized()) 101 // To avoid running into deadlocks while we stop the thread, shut it down
92 return; 102 // via a local variable while not holding the audio thread lock.
103 scoped_ptr<base::Thread> audio_thread;
104 {
105 base::AutoLock lock(audio_thread_lock_);
106 audio_thread_.swap(audio_thread);
107 }
93 108
94 DCHECK_NE(MessageLoop::current(), GetMessageLoop()); 109 if (!audio_thread.get())
110 return;
111
112 CHECK_NE(MessageLoop::current(), audio_thread->message_loop());
95 113
96 // We must use base::Unretained since Shutdown might have been called from 114 // We must use base::Unretained since Shutdown might have been called from
97 // the destructor and we can't alter the refcount of the object at that point. 115 // the destructor and we can't alter the refcount of the object at that point.
98 GetMessageLoop()->PostTask(FROM_HERE, base::Bind( 116 audio_thread->message_loop()->PostTask(FROM_HERE, base::Bind(
99 &AudioManagerBase::ShutdownOnAudioThread, 117 &AudioManagerBase::ShutdownOnAudioThread,
100 base::Unretained(this))); 118 base::Unretained(this)));
119
101 // Stop() will wait for any posted messages to be processed first. 120 // Stop() will wait for any posted messages to be processed first.
102 audio_thread_.Stop(); 121 audio_thread->Stop();
103 } 122 }
104 123
105 void AudioManagerBase::ShutdownOnAudioThread() { 124 void AudioManagerBase::ShutdownOnAudioThread() {
106 DCHECK_EQ(MessageLoop::current(), GetMessageLoop()); 125 // This should always be running on the audio thread, but since we've cleared
107 126 // the audio_thread_ member pointer when we get here, we can't verify exactly
127 // what thread we're running on. The method is not public though and only
128 // called from one place, so we'll leave it at that.
108 AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin(); 129 AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin();
109 for (; it != output_dispatchers_.end(); ++it) { 130 for (; it != output_dispatchers_.end(); ++it) {
110 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second; 131 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second;
111 if (dispatcher) { 132 if (dispatcher) {
112 dispatcher->Shutdown(); 133 dispatcher->Shutdown();
113 // All AudioOutputProxies must have been freed before Shutdown is called. 134 // All AudioOutputProxies must have been freed before Shutdown is called.
114 // If they still exist, things will go bad. They have direct pointers to 135 // If they still exist, things will go bad. They have direct pointers to
115 // both physical audio stream objects that belong to the dispatcher as 136 // both physical audio stream objects that belong to the dispatcher as
116 // well as the message loop of the audio thread that will soon go away. 137 // well as the message loop of the audio thread that will soon go away.
117 // So, better crash now than later. 138 // So, better crash now than later.
118 CHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; 139 CHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive";
119 dispatcher = NULL; 140 dispatcher = NULL;
120 } 141 }
121 } 142 }
122 143
123 output_dispatchers_.clear(); 144 output_dispatchers_.clear();
124 } 145 }
OLDNEW
« no previous file with comments | « media/audio/audio_manager_base.h ('k') | media/audio/audio_output_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698