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( | |
| 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 |
| OLD | NEW |