OLD | NEW |
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 Loading... |
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 } |
OLD | NEW |