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

Side by Side Diff: content/browser/renderer_host/media/audio_input_device_manager.cc

Issue 8677012: Refactor the AudioInputDeviceManager by removing the device thread. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 1 month 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "content/browser/renderer_host/media/audio_input_device_manager.h" 5 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "content/browser/renderer_host/media/audio_input_device_manager_event_h andler.h" 9 #include "content/browser/renderer_host/media/audio_input_device_manager_event_h andler.h"
10 #include "content/public/browser/browser_thread.h" 10 #include "content/public/browser/browser_thread.h"
11 #include "media/audio/audio_manager_base.h" 11 #include "media/audio/audio_manager_base.h"
12 12
13 using content::BrowserThread; 13 using content::BrowserThread;
14 14
15 namespace media_stream { 15 namespace media_stream {
16 16
17 const int AudioInputDeviceManager::kFakeOpenSessionId = 1; 17 const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
18 const int AudioInputDeviceManager::kInvalidSessionId = 0; 18 const int AudioInputDeviceManager::kInvalidSessionId = 0;
19 const char AudioInputDeviceManager::kInvalidDeviceId[] = ""; 19 const char AudioInputDeviceManager::kInvalidDeviceId[] = "";
20 20
21 // Starting id for the first capture session. 21 // Starting id for the first capture session.
22 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1; 22 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1;
23 23
24 // Helper function.
25 static bool IsValidAudioInputDevice(const media::AudioDeviceName& device) {
26 AudioManager* audio_manager = AudioManager::GetAudioManager();
27 if (!audio_manager)
28 return false;
29
30 // Get the up-to-date list of devices and verify the device is in the list.
31 media::AudioDeviceNames device_names;
32 audio_manager->GetAudioInputDeviceNames(&device_names);
33 if (!device_names.empty()) {
34 for (media::AudioDeviceNames::iterator iter = device_names.begin();
35 iter != device_names.end();
36 ++iter) {
37 if (iter->device_name == device.device_name &&
38 iter->unique_id == device.unique_id)
39 return true;
40 }
41 }
42 // The device wasn't found.
43 return false;
44 }
45
46 AudioInputDeviceManager::AudioInputDeviceManager() 24 AudioInputDeviceManager::AudioInputDeviceManager()
47 : audio_input_device_thread_("AudioInputDeviceManagerThread"), 25 : listener_(NULL),
48 listener_(NULL),
49 next_capture_session_id_(kFirstSessionId) { 26 next_capture_session_id_(kFirstSessionId) {
50 audio_input_device_thread_.Start();
51 } 27 }
52 28
53 AudioInputDeviceManager::~AudioInputDeviceManager() { 29 AudioInputDeviceManager::~AudioInputDeviceManager() {
54 audio_input_device_thread_.Stop();
55 } 30 }
56 31
57 void AudioInputDeviceManager::Register(MediaStreamProviderListener* listener) { 32 void AudioInputDeviceManager::Register(MediaStreamProviderListener* listener) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
59 DCHECK(!listener_); 34 DCHECK(!listener_);
60 listener_ = listener; 35 listener_ = listener;
61 } 36 }
62 37
63 void AudioInputDeviceManager::Unregister() { 38 void AudioInputDeviceManager::Unregister() {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
65 DCHECK(listener_); 40 DCHECK(listener_);
66 listener_ = NULL; 41 listener_ = NULL;
67 } 42 }
68 43
69 void AudioInputDeviceManager::EnumerateDevices() { 44 void AudioInputDeviceManager::EnumerateDevices() {
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71 DCHECK(listener_); 46 DCHECK(listener_);
72 47
73 audio_input_device_thread_.message_loop()->PostTask(
74 FROM_HERE,
75 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread,
76 base::Unretained(this)));
77 }
78
79 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
81
82 // Generate a new id for this device.
83 int audio_input_session_id = next_capture_session_id_++;
84
85 audio_input_device_thread_.message_loop()->PostTask(
86 FROM_HERE,
87 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread,
88 base::Unretained(this), audio_input_session_id, device));
89
90 return audio_input_session_id;
91 }
92
93 void AudioInputDeviceManager::Close(int session_id) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
95 DCHECK(listener_);
96
97 audio_input_device_thread_.message_loop()->PostTask(
98 FROM_HERE,
99 base::Bind(&AudioInputDeviceManager::CloseOnDeviceThread,
100 base::Unretained(this), session_id));
101 }
102
103 void AudioInputDeviceManager::Start(
104 int session_id, AudioInputDeviceManagerEventHandler* event_handler) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106 DCHECK(event_handler);
107
108 // Solution for not using MediaStreamManager. This is needed when Start() is
109 // called without using Open(), we post default device for test purpose.
110 // And we do not store the info for the kFakeOpenSessionId but return
111 // the callback immediately.
112 if (session_id == kFakeOpenSessionId) {
113 event_handler->OnDeviceStarted(session_id,
114 AudioManagerBase::kDefaultDeviceId);
115 return;
116 }
117
118 // If session has been started, post a callback with an error.
119 if (event_handlers_.find(session_id) != event_handlers_.end()) {
120 // Session has been started, post a callback with error.
121 event_handler->OnDeviceStarted(session_id, kInvalidDeviceId);
122 return;
123 }
124
125 // Add the event handler to the session.
126 event_handlers_.insert(std::make_pair(session_id, event_handler));
127
128 audio_input_device_thread_.message_loop()->PostTask(
129 FROM_HERE,
130 base::Bind(&AudioInputDeviceManager::StartOnDeviceThread,
131 base::Unretained(this), session_id));
132 }
133
134 void AudioInputDeviceManager::Stop(int session_id) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136
137 audio_input_device_thread_.message_loop()->PostTask(
138 FROM_HERE,
139 base::Bind(&AudioInputDeviceManager::StopOnDeviceThread,
140 base::Unretained(this), session_id));
141 }
142
143 void AudioInputDeviceManager::EnumerateOnDeviceThread() {
144 DCHECK(IsOnCaptureDeviceThread());
145
146 // Get the device list from system. 48 // Get the device list from system.
147 media::AudioDeviceNames device_names; 49 media::AudioDeviceNames device_names;
148 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); 50 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names);
149 51
150 StreamDeviceInfoArray devices; 52 StreamDeviceInfoArray devices;
151 for (media::AudioDeviceNames::iterator it = device_names.begin(); 53 for (media::AudioDeviceNames::iterator it = device_names.begin();
152 it != device_names.end(); 54 it != device_names.end();
153 ++it) { 55 ++it) {
154 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name, 56 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name,
155 it->unique_id, false)); 57 it->unique_id, false));
156 } 58 }
157 59
60 // Returns the device list through the listener by posting a task on
61 // IO thread since MediaStreamManager handles the callback asynchronously.
158 BrowserThread::PostTask( 62 BrowserThread::PostTask(
159 BrowserThread::IO, 63 BrowserThread::IO,
160 FROM_HERE, 64 FROM_HERE,
161 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, 65 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread,
162 base::Unretained(this), devices)); 66 base::Unretained(this),
67 devices));
tommi (sloooow) - chröme 2011/11/23 20:16:31 won't |devices| go out of scope and thus be garbag
no longer working on chromium 2011/11/24 14:47:34 I did not dig into the details on how the bind wor
henrika (OOO until Aug 14) 2011/11/24 15:22:26 Can probably be done without a copy.
no longer working on chromium 2011/11/24 16:00:42 Use a pointer as Tommi suggests.
163 } 68 }
164 69
165 void AudioInputDeviceManager::OpenOnDeviceThread( 70 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) {
166 int session_id, const StreamDeviceInfo& device) { 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
167 DCHECK(IsOnCaptureDeviceThread()); 72
73 // Generate a new id for this device.
74 int session_id = next_capture_session_id_++;
168 DCHECK(devices_.find(session_id) == devices_.end()); 75 DCHECK(devices_.find(session_id) == devices_.end());
169 76
170 media::AudioDeviceName audio_input_device_name; 77 media::AudioDeviceName audio_input_device_name;
171 audio_input_device_name.device_name = device.name; 78 audio_input_device_name.device_name = device.name;
172 audio_input_device_name.unique_id = device.device_id; 79 audio_input_device_name.unique_id = device.device_id;
173 80
174 // Check if the device is valid
175 if (!IsValidAudioInputDevice(audio_input_device_name)) {
176 SignalError(session_id, kDeviceNotAvailable);
177 return;
178 }
179
180 // Add the session_id and device to the list. 81 // Add the session_id and device to the list.
181 devices_[session_id] = audio_input_device_name; 82 devices_[session_id] = audio_input_device_name;
83
84 // Returns the |session_id| through the listener by posting a task on
85 // IO thread since MediaStreamManager handles the callback asynchronously.
182 BrowserThread::PostTask(BrowserThread::IO, 86 BrowserThread::PostTask(BrowserThread::IO,
183 FROM_HERE, 87 FROM_HERE,
184 base::Bind( 88 base::Bind(
185 &AudioInputDeviceManager::OpenedOnIOThread, 89 &AudioInputDeviceManager::OpenedOnIOThread,
henrika (OOO until Aug 14) 2011/11/24 15:22:26 Odd indentation.
no longer working on chromium 2011/11/24 16:00:42 Done.
186 base::Unretained(this), 90 base::Unretained(this),
187 session_id)); 91 session_id));
92
93 return session_id;
188 } 94 }
189 95
190 void AudioInputDeviceManager::CloseOnDeviceThread(int session_id) { 96 void AudioInputDeviceManager::Close(int session_id) {
191 DCHECK(IsOnCaptureDeviceThread()); 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
98 DCHECK(listener_);
192 DCHECK(devices_.find(session_id) != devices_.end()); 99 DCHECK(devices_.find(session_id) != devices_.end());
193 100
194 devices_.erase(session_id); 101 devices_.erase(session_id);
102
103 // Checks if the device has been stopped, if not, sends stop signal.
104 EventHandlerMap::iterator it = event_handlers_.find(session_id);
105 if (it != event_handlers_.end()) {
106 it->second->OnDeviceStopped(session_id);
107 event_handlers_.erase(session_id);
108 }
109
110 // Posts a callback through the listener on IO thread since
111 // MediaStreamManager handles the callback asynchronously.
195 BrowserThread::PostTask(BrowserThread::IO, 112 BrowserThread::PostTask(BrowserThread::IO,
196 FROM_HERE, 113 FROM_HERE,
197 base::Bind( 114 base::Bind(
198 &AudioInputDeviceManager::ClosedOnIOThread, 115 &AudioInputDeviceManager::ClosedOnIOThread,
henrika (OOO until Aug 14) 2011/11/24 15:22:26 Fix indentation.
no longer working on chromium 2011/11/24 16:00:42 Done.
199 base::Unretained(this), 116 base::Unretained(this),
200 session_id)); 117 session_id));
201 } 118 }
202 119
203 void AudioInputDeviceManager::StartOnDeviceThread(const int session_id) { 120 void AudioInputDeviceManager::Start(
204 DCHECK(IsOnCaptureDeviceThread()); 121 int session_id, AudioInputDeviceManagerEventHandler* event_handler) {
tommi (sloooow) - chröme 2011/11/23 20:16:31 move int session_id to the previous line
no longer working on chromium 2011/11/24 14:47:34 "AudioInputDeviceManagerEventHandler* event_handle
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
123 DCHECK(event_handler);
205 124
206 // Get the up-to-date device enumeration list from the OS and find out 125 // Solution for not using MediaStreamManager. This is needed when Start() is
207 // the unique id of the device. 126 // called without using Open(), we post default device for test purpose.
208 std::string device_id = kInvalidDeviceId; 127 // And we do not store the info for the kFakeOpenSessionId but return
209 AudioInputDeviceMap::const_iterator it = devices_.find(session_id); 128 // the callback immediately.
210 if (it != devices_.end()) { 129 if (session_id == kFakeOpenSessionId) {
211 media::AudioDeviceNames device_names; 130 event_handler->OnDeviceStarted(session_id,
212 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); 131 AudioManagerBase::kDefaultDeviceId);
213 if (!device_names.empty()) { 132 return;
214 int index = 0;
215 for (media::AudioDeviceNames::iterator iter = device_names.begin();
216 iter != device_names.end();
217 ++iter, ++index) {
218 if (iter->device_name == it->second.device_name &&
219 iter->unique_id == it->second.unique_id) {
220 // Found the device.
221 device_id = iter->unique_id;
222 break;
223 }
224 }
225 }
226 } 133 }
227 134
228 // Posts the index to AudioInputRenderHost through the event handler. 135 // Checks if the device has been opened or not.
229 BrowserThread::PostTask(BrowserThread::IO, 136 std::string device_id = (devices_.find(session_id) == devices_.end()) ?
230 FROM_HERE, 137 kInvalidDeviceId : devices_[session_id].unique_id;
231 base::Bind( 138
232 &AudioInputDeviceManager::StartedOnIOThread, 139 // Adds the event handler to the session if the session has not been started,
233 base::Unretained(this), 140 // otherwise post a |kInvalidDeviceId| to indicate that Start() fails.
234 session_id, 141 if (event_handlers_.find(session_id) == event_handlers_.end())
235 device_id)); 142 event_handlers_.insert(std::make_pair(session_id, event_handler));
143 else
144 device_id = kInvalidDeviceId;
145
146 // Post a callback through the AudioInputRendererHost to notify the renderer
147 // device has been started.
148 event_handler->OnDeviceStarted(session_id, device_id);
236 } 149 }
237 150
238 void AudioInputDeviceManager::StopOnDeviceThread(int session_id) { 151 void AudioInputDeviceManager::Stop(int session_id) {
239 DCHECK(IsOnCaptureDeviceThread()); 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
240 BrowserThread::PostTask(BrowserThread::IO, 153
241 FROM_HERE, 154 // Erase the event handler referenced by the session_id.
242 base::Bind( 155 event_handlers_.erase(session_id);
243 &AudioInputDeviceManager::StoppedOnIOThread,
244 base::Unretained(this),
245 session_id));
246 } 156 }
247 157
248 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( 158 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
249 const StreamDeviceInfoArray& devices) { 159 const StreamDeviceInfoArray& devices) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251 if (listener_) 161 if (listener_)
252 listener_->DevicesEnumerated(kAudioCapture, devices); 162 listener_->DevicesEnumerated(kAudioCapture, devices);
253 } 163 }
254 164
255 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { 165 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
257 if (listener_) 167 if (listener_)
258 listener_->Opened(kAudioCapture, session_id); 168 listener_->Opened(kAudioCapture, session_id);
259 } 169 }
260 170
261 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { 171 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263 EventHandlerMap::iterator it = event_handlers_.find(session_id);
264 if (it != event_handlers_.end()) {
265 // The device hasn't been stopped, send stop signal.
266 it->second->OnDeviceStopped(session_id);
267 event_handlers_.erase(session_id);
268 }
269 listener_->Closed(kAudioCapture, session_id);
270 }
271
272
273 void AudioInputDeviceManager::ErrorOnIOThread(int session_id,
274 MediaStreamProviderError error) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 if (listener_) 173 if (listener_)
277 listener_->Error(kAudioCapture, session_id, error); 174 listener_->Closed(kAudioCapture, session_id);
278 }
279
280 void AudioInputDeviceManager::StartedOnIOThread(
281 int session_id, const std::string& device_id) {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
283
284 EventHandlerMap::iterator it = event_handlers_.find(session_id);
285 if (it == event_handlers_.end())
286 return;
287
288 // Post a callback through the AudioInputRendererHost to notify the renderer
289 // device has been started.
290 it->second->OnDeviceStarted(session_id, device_id);
291 }
292
293 void AudioInputDeviceManager::StoppedOnIOThread(int session_id) {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295 // Erase the event handler referenced by the session_id.
296 event_handlers_.erase(session_id);
297 }
298
299 void AudioInputDeviceManager::SignalError(int session_id,
300 MediaStreamProviderError error) {
301 BrowserThread::PostTask(BrowserThread::IO,
302 FROM_HERE,
303 base::Bind(
304 &AudioInputDeviceManager::ErrorOnIOThread,
305 base::Unretained(this),
306 session_id,
307 error));
308 }
309
310 bool AudioInputDeviceManager::IsOnCaptureDeviceThread() const {
311 return MessageLoop::current() == audio_input_device_thread_.message_loop();
312 }
313
314 void AudioInputDeviceManager::UnregisterEventHandler(int session_id) {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
316 event_handlers_.erase(session_id);
317 }
318
319 bool AudioInputDeviceManager::HasEventHandler(int session_id) {
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
321 return event_handlers_.find(session_id) != event_handlers_.end();
322 }
323
324 MessageLoop* AudioInputDeviceManager::message_loop() {
325 return audio_input_device_thread_.message_loop();
326 } 175 }
327 176
328 } // namespace media_stream 177 } // namespace media_stream
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698