Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| OLD | NEW |