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

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: fixed the comments Created 9 years 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( 48 media::AudioDeviceNames device_names;
49 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names);
wjia(left Chromium) 2011/11/25 16:37:20 How much time does this operation typically take?
no longer working on chromium 2011/11/25 16:45:33 I think it should be fine. My tests shows that it
50
51 StreamDeviceInfoArray* devices = new StreamDeviceInfoArray;
52 for (media::AudioDeviceNames::iterator it = device_names.begin();
53 it != device_names.end();
54 ++it) {
55 devices->push_back(StreamDeviceInfo(kAudioCapture, it->device_name,
56 it->unique_id, false));
wjia(left Chromium) 2011/11/25 16:37:20 nit: indent. one more space.
no longer working on chromium 2011/11/25 16:45:33 Done.
57 }
58
59 // Returns the device list through the listener by posting a task on
60 // IO thread since MediaStreamManager handles the callback asynchronously.
61 BrowserThread::PostTask(
62 BrowserThread::IO,
74 FROM_HERE, 63 FROM_HERE,
75 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread, 64 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread,
76 base::Unretained(this))); 65 base::Unretained(this),
66 devices));
77 } 67 }
78 68
79 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { 69 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
81 71
82 // Generate a new id for this device. 72 // Generates a new id for this device.
83 int audio_input_session_id = next_capture_session_id_++; 73 int session_id = next_capture_session_id_++;
74 DCHECK(devices_.find(session_id) == devices_.end());
84 75
85 audio_input_device_thread_.message_loop()->PostTask( 76 media::AudioDeviceName audio_input_device_name;
86 FROM_HERE, 77 audio_input_device_name.device_name = device.name;
87 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, 78 audio_input_device_name.unique_id = device.device_id;
88 base::Unretained(this), audio_input_session_id, device));
89 79
wjia(left Chromium) 2011/11/25 16:37:20 There was an error check (if device is valid) in p
no longer working on chromium 2011/11/25 16:45:33 No, it is not needed any more. Since checking the
90 return audio_input_session_id; 80 // Adds the session_id and device to the list.
81 devices_[session_id] = audio_input_device_name;
82
83 // Returns the |session_id| through the listener by posting a task on
84 // IO thread since MediaStreamManager handles the callback asynchronously.
85 BrowserThread::PostTask(BrowserThread::IO,
86 FROM_HERE,
87 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread,
88 base::Unretained(this),
89 session_id));
90
91 return session_id;
91 } 92 }
92 93
93 void AudioInputDeviceManager::Close(int session_id) { 94 void AudioInputDeviceManager::Close(int session_id) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
95 DCHECK(listener_); 96 DCHECK(listener_);
96 97
97 audio_input_device_thread_.message_loop()->PostTask( 98 if (devices_.find(session_id) != devices_.end())
98 FROM_HERE, 99 devices_.erase(session_id);
99 base::Bind(&AudioInputDeviceManager::CloseOnDeviceThread, 100
100 base::Unretained(this), session_id)); 101 // Checks if the device has been stopped, if not, send stop signal.
102 EventHandlerMap::iterator it = event_handlers_.find(session_id);
103 if (it != event_handlers_.end()) {
104 it->second->OnDeviceStopped(session_id);
105 event_handlers_.erase(session_id);
106 }
107
108 // Posts a callback through the listener on IO thread since
109 // MediaStreamManager handles the callback asynchronously.
110 BrowserThread::PostTask(BrowserThread::IO,
111 FROM_HERE,
112 base::Bind(&AudioInputDeviceManager::ClosedOnIOThread,
113 base::Unretained(this),
114 session_id));
101 } 115 }
102 116
103 void AudioInputDeviceManager::Start( 117 void AudioInputDeviceManager::Start(
104 int session_id, AudioInputDeviceManagerEventHandler* event_handler) { 118 int session_id, AudioInputDeviceManagerEventHandler* event_handler) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106 DCHECK(event_handler); 120 DCHECK(event_handler);
107 121
108 // Solution for not using MediaStreamManager. This is needed when Start() is 122 // Solution for not using MediaStreamManager. This is needed when Start() is
109 // called without using Open(), we post default device for test purpose. 123 // called without using Open(), we post default device for test purpose.
110 // And we do not store the info for the kFakeOpenSessionId but return 124 // And we do not store the info for the kFakeOpenSessionId but return
111 // the callback immediately. 125 // the callback immediately.
112 if (session_id == kFakeOpenSessionId) { 126 if (session_id == kFakeOpenSessionId) {
113 event_handler->OnDeviceStarted(session_id, 127 event_handler->OnDeviceStarted(session_id,
114 AudioManagerBase::kDefaultDeviceId); 128 AudioManagerBase::kDefaultDeviceId);
115 return; 129 return;
116 } 130 }
117 131
118 // If session has been started, post a callback with an error. 132 // Checks if the device has been opened or not.
119 if (event_handlers_.find(session_id) != event_handlers_.end()) { 133 std::string device_id = (devices_.find(session_id) == devices_.end()) ?
120 // Session has been started, post a callback with error. 134 kInvalidDeviceId : devices_[session_id].unique_id;
121 event_handler->OnDeviceStarted(session_id, kInvalidDeviceId);
122 return;
123 }
124 135
125 // Add the event handler to the session. 136 // Adds the event handler to the session if the session has not been started,
126 event_handlers_.insert(std::make_pair(session_id, event_handler)); 137 // otherwise post a |kInvalidDeviceId| to indicate that Start() fails.
138 if (event_handlers_.find(session_id) == event_handlers_.end())
139 event_handlers_.insert(std::make_pair(session_id, event_handler));
140 else
141 device_id = kInvalidDeviceId;
127 142
128 audio_input_device_thread_.message_loop()->PostTask( 143 // Posts a callback through the AudioInputRendererHost to notify the renderer
129 FROM_HERE, 144 // that the device has started.
130 base::Bind(&AudioInputDeviceManager::StartOnDeviceThread, 145 event_handler->OnDeviceStarted(session_id, device_id);
131 base::Unretained(this), session_id));
132 } 146 }
133 147
134 void AudioInputDeviceManager::Stop(int session_id) { 148 void AudioInputDeviceManager::Stop(int session_id) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136 150
137 audio_input_device_thread_.message_loop()->PostTask( 151 // Erases the event handler referenced by the session_id.
138 FROM_HERE, 152 event_handlers_.erase(session_id);
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.
147 media::AudioDeviceNames device_names;
148 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names);
149
150 StreamDeviceInfoArray devices;
151 for (media::AudioDeviceNames::iterator it = device_names.begin();
152 it != device_names.end();
153 ++it) {
154 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name,
155 it->unique_id, false));
156 }
157
158 BrowserThread::PostTask(
159 BrowserThread::IO,
160 FROM_HERE,
161 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread,
162 base::Unretained(this), devices));
163 }
164
165 void AudioInputDeviceManager::OpenOnDeviceThread(
166 int session_id, const StreamDeviceInfo& device) {
167 DCHECK(IsOnCaptureDeviceThread());
168 DCHECK(devices_.find(session_id) == devices_.end());
169
170 media::AudioDeviceName audio_input_device_name;
171 audio_input_device_name.device_name = device.name;
172 audio_input_device_name.unique_id = device.device_id;
173
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.
181 devices_[session_id] = audio_input_device_name;
182 BrowserThread::PostTask(BrowserThread::IO,
183 FROM_HERE,
184 base::Bind(
185 &AudioInputDeviceManager::OpenedOnIOThread,
186 base::Unretained(this),
187 session_id));
188 }
189
190 void AudioInputDeviceManager::CloseOnDeviceThread(int session_id) {
191 DCHECK(IsOnCaptureDeviceThread());
192 DCHECK(devices_.find(session_id) != devices_.end());
193
194 devices_.erase(session_id);
195 BrowserThread::PostTask(BrowserThread::IO,
196 FROM_HERE,
197 base::Bind(
198 &AudioInputDeviceManager::ClosedOnIOThread,
199 base::Unretained(this),
200 session_id));
201 }
202
203 void AudioInputDeviceManager::StartOnDeviceThread(const int session_id) {
204 DCHECK(IsOnCaptureDeviceThread());
205
206 // Get the up-to-date device enumeration list from the OS and find out
207 // the unique id of the device.
208 std::string device_id = kInvalidDeviceId;
209 AudioInputDeviceMap::const_iterator it = devices_.find(session_id);
210 if (it != devices_.end()) {
211 media::AudioDeviceNames device_names;
212 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names);
213 if (!device_names.empty()) {
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 }
227
228 // Posts the index to AudioInputRenderHost through the event handler.
229 BrowserThread::PostTask(BrowserThread::IO,
230 FROM_HERE,
231 base::Bind(
232 &AudioInputDeviceManager::StartedOnIOThread,
233 base::Unretained(this),
234 session_id,
235 device_id));
236 }
237
238 void AudioInputDeviceManager::StopOnDeviceThread(int session_id) {
239 DCHECK(IsOnCaptureDeviceThread());
240 BrowserThread::PostTask(BrowserThread::IO,
241 FROM_HERE,
242 base::Bind(
243 &AudioInputDeviceManager::StoppedOnIOThread,
244 base::Unretained(this),
245 session_id));
246 } 153 }
247 154
248 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( 155 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
249 const StreamDeviceInfoArray& devices) { 156 StreamDeviceInfoArray* devices) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
158 // Ensures that |devices| gets deleted on exit.
159 scoped_ptr<StreamDeviceInfoArray> devices_array(devices);
251 if (listener_) 160 if (listener_)
252 listener_->DevicesEnumerated(kAudioCapture, devices); 161 listener_->DevicesEnumerated(kAudioCapture, *devices_array);
253 } 162 }
254 163
255 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { 164 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
257 if (listener_) 166 if (listener_)
258 listener_->Opened(kAudioCapture, session_id); 167 listener_->Opened(kAudioCapture, session_id);
259 } 168 }
260 169
261 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { 170 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 171 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_) 172 if (listener_)
277 listener_->Error(kAudioCapture, session_id, error); 173 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 } 174 }
327 175
328 } // namespace media_stream 176 } // namespace media_stream
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698