Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/renderer_host/media/media_stream_manager.h" | |
| 6 | |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/rand_util.h" | |
| 10 #include "content/browser/browser_thread.h" | |
| 11 #include "content/browser/renderer_host/media/media_stream_device_settings.h" | |
| 12 #include "content/browser/renderer_host/media/media_stream_requester.h" | |
| 13 #include "content/browser/renderer_host/media/video_capture_manager.h" | |
| 14 #include "content/common/media/media_stream_options.h" | |
| 15 | |
| 16 namespace media_stream { | |
| 17 | |
| 18 // TODO(mflodman) Find out who should own MediaStreamManager. | |
| 19 base::LazyInstance<MediaStreamManager> g_media_stream_manager( | |
| 20 base::LINKER_INITIALIZED); | |
| 21 | |
| 22 // Creates a random label used to identify requests. | |
| 23 static std::string RandomLabel() { | |
| 24 static const char alphabet[] = "0123456789" | |
| 25 "abcdefghijklmnopqrstuvwxyz" | |
| 26 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| 27 | |
| 28 std::string label(63, ' '); | |
| 29 for (size_t i = 0; i < label.size(); ++i) { | |
| 30 int random_char = base::RandGenerator(sizeof(alphabet - 1)); | |
|
wjia(left Chromium)
2011/07/01 03:58:34
would it be "sizeof(alphabet) - 1"?
mflodman1
2011/07/01 09:37:10
Yes, you're right. Otherwise we'll end up with onl
| |
| 31 label[i] = alphabet[random_char]; | |
| 32 } | |
| 33 return label; | |
| 34 } | |
| 35 | |
| 36 // Helper to verify if a media stream type is part of options or not. | |
| 37 static bool Requested(const StreamOptions& options, | |
| 38 MediaStreamType stream_type) { | |
| 39 if (stream_type == kVideoCapture | |
| 40 && (options.video_option != StreamOptions::kNoCamera)) { | |
| 41 return true; | |
| 42 } else if (stream_type == kAudioCapture && options.audio == true) { | |
| 43 return true; | |
| 44 } | |
| 45 return false; | |
| 46 } | |
| 47 | |
| 48 MediaStreamManager* MediaStreamManager::Get() { | |
| 49 return g_media_stream_manager.Pointer(); | |
| 50 } | |
| 51 | |
| 52 MediaStreamManager::~MediaStreamManager() { | |
| 53 delete device_settings_; | |
| 54 delete video_capture_manager_; | |
| 55 } | |
| 56 | |
| 57 VideoCaptureManager* MediaStreamManager::GetVideoCaptureManager() { | |
| 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 59 return video_capture_manager_; | |
| 60 } | |
| 61 | |
| 62 void MediaStreamManager::GenerateStream(MediaStreamRequester* requester, | |
| 63 int render_process_id, | |
| 64 int render_view_id, | |
| 65 const StreamOptions& options, | |
| 66 const std::string& security_origin, | |
| 67 std::string* label) { | |
| 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 69 | |
| 70 // TODO(mflodman) Remove next line when audio is supported. | |
| 71 (const_cast<StreamOptions&>(options)).audio = false; | |
| 72 | |
| 73 // Create a new request based on options. | |
| 74 DeviceRequest new_request = DeviceRequest(requester, options); | |
| 75 if (Requested(new_request.options, kAudioCapture)) { | |
| 76 new_request.state[kAudioCapture] = DeviceRequest::kRequested; | |
| 77 } | |
| 78 if (Requested(new_request.options, kVideoCapture)) { | |
| 79 new_request.state[kVideoCapture] = DeviceRequest::kRequested; | |
| 80 } | |
| 81 | |
| 82 // Create a label for this request and verify it is unique. | |
| 83 new_request.label = RandomLabel(); | |
| 84 for (DeviceRequestList::iterator it = requests_.begin(); | |
| 85 it != requests_.end(); ++it) { | |
| 86 if (new_request.label == it->label) { | |
| 87 new_request.label = RandomLabel(); | |
| 88 it = requests_.begin(); | |
| 89 } | |
| 90 } | |
| 91 requests_.push_back(new_request); | |
| 92 | |
| 93 // Get user confirmation to use capture devices. | |
| 94 device_settings_->RequestCaptureDeviceUsage(new_request.label, | |
| 95 render_process_id, render_view_id, | |
| 96 options, security_origin); | |
| 97 (*label) = new_request.label; | |
| 98 } | |
| 99 | |
| 100 void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) { | |
| 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 102 | |
| 103 DeviceRequestList::iterator it = requests_.begin(); | |
| 104 while (it != requests_.end()) { | |
| 105 if (it->requester == requester && !RequestDone(*it)) { | |
| 106 it = requests_.erase(it); | |
| 107 it = requests_.begin(); | |
| 108 } else { | |
| 109 ++it; | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 void MediaStreamManager::StopGeneratedStream(const std::string& label) { | |
| 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 116 // Find the request and close all open devices for the request. | |
| 117 for (DeviceRequestList::iterator it = requests_.begin(); | |
| 118 it != requests_.end(); ++it) { | |
| 119 if (it->label == label) { | |
| 120 for (StreamDeviceInfoArray::iterator audio_it = it->audio_devices.begin(); | |
| 121 audio_it != it->audio_devices.end(); ++audio_it) { | |
| 122 // TODO(mflodman) Add code when audio input manager exists. | |
| 123 DCHECK(false); | |
| 124 } | |
| 125 for (StreamDeviceInfoArray::iterator video_it = it->video_devices.begin(); | |
| 126 video_it != it->video_devices.end(); ++video_it) { | |
| 127 video_capture_manager_->Close(video_it->session_id); | |
| 128 } | |
| 129 requests_.erase(it); | |
| 130 return; | |
| 131 } | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 void MediaStreamManager::Opened(MediaStreamType stream_type, | |
| 136 int capture_session_id) { | |
| 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 138 | |
| 139 // Find the request containing this device and mark it as used. | |
| 140 DeviceRequest* request = NULL; | |
| 141 StreamDeviceInfo* device = NULL; | |
| 142 for (DeviceRequestList::iterator request_it = requests_.begin(); | |
| 143 request_it != requests_.end() && request == NULL; ++request_it) { | |
| 144 StreamDeviceInfoArray* devices = NULL; | |
| 145 if (stream_type == kAudioCapture) { | |
| 146 devices = &(request_it->audio_devices); | |
| 147 } else if (stream_type == kVideoCapture) { | |
| 148 devices = &(request_it->video_devices); | |
| 149 } else { | |
| 150 DCHECK(false); | |
| 151 } | |
| 152 | |
| 153 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); | |
| 154 device_it != devices->end(); ++device_it) { | |
| 155 if (device_it->session_id == capture_session_id) { | |
| 156 // We've found the request. | |
| 157 | |
| 158 request = &(*request_it); | |
| 159 device = &(*device_it); | |
| 160 break; | |
| 161 } | |
| 162 } | |
| 163 } | |
| 164 if (request == NULL) { | |
| 165 // The request doesn't exist. | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 device->in_use = true; | |
| 170 if (!RequestDone(*request)) { | |
| 171 // Wait for more devices to be opened before we're done. | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 if (request->state[kAudioCapture] == DeviceRequest::kOpening) { | |
| 176 request->state[kAudioCapture] = DeviceRequest::kDone; | |
| 177 } | |
| 178 if (request->state[kVideoCapture] == DeviceRequest::kOpening) { | |
| 179 request->state[kVideoCapture] = DeviceRequest::kDone; | |
| 180 } | |
| 181 | |
| 182 request->requester->StreamGenerated(request->label, request->audio_devices, | |
| 183 request->video_devices); | |
| 184 } | |
| 185 | |
| 186 void MediaStreamManager::Closed(MediaStreamType stream_type, | |
| 187 int capture_session_id) { | |
| 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 189 } | |
| 190 | |
| 191 void MediaStreamManager::DevicesEnumerated( | |
| 192 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { | |
| 193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 194 | |
| 195 // Publish the result for all requests waiting for device list(s). | |
| 196 // Find the requests waiting for this device list, store their labels and | |
| 197 // release the iterator before calling device settings. We might get a call | |
| 198 // back from device_settings that will need to iterate through devices. | |
| 199 std::list<std::string> label_list; | |
| 200 for (DeviceRequestList::iterator it = requests_.begin(); | |
| 201 it != requests_.end(); ++it) { | |
| 202 if (it->state[stream_type] == DeviceRequest::kRequested | |
| 203 && Requested(it->options, stream_type)) { | |
| 204 label_list.push_back(it->label); | |
| 205 } | |
| 206 } | |
| 207 while (label_list.size()) { | |
| 208 device_settings_->AvailableDevices(label_list.front(), stream_type, | |
| 209 devices); | |
| 210 label_list.pop_front(); | |
| 211 } | |
| 212 enumeration_in_progress_[stream_type] = false; | |
| 213 } | |
| 214 | |
| 215 void MediaStreamManager::Error(MediaStreamType stream_type, | |
| 216 int capture_session_id, | |
| 217 MediaStreamProviderError error) { | |
| 218 // Find the device for the error call. | |
| 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 220 for (DeviceRequestList::iterator it = requests_.begin(); | |
| 221 it != requests_.end(); ++it) { | |
| 222 StreamDeviceInfoArray* devices = NULL; | |
| 223 if (stream_type == kAudioCapture) { | |
| 224 devices = &(it->audio_devices); | |
| 225 } else if (stream_type == kVideoCapture) { | |
| 226 devices = &(it->video_devices); | |
| 227 } else { | |
| 228 DCHECK(false); | |
| 229 } | |
| 230 | |
| 231 int device_idx = 0; | |
| 232 for (StreamDeviceInfoArray::iterator device_it = devices->begin(); | |
| 233 device_it != devices->end(); ++device_it, ++device_idx) { | |
| 234 if (device_it->session_id == capture_session_id) { | |
| 235 // We've found the failing device. Find the error case: | |
| 236 if (it->state[stream_type] == DeviceRequest::kDone) { | |
| 237 // 1. Already opened -> signal device failure and close device. | |
| 238 // Use device_idx to signal which of the devices encountered an | |
| 239 // error. | |
| 240 if (stream_type == kAudioCapture) { | |
| 241 it->requester->AudioDeviceFailed(it->label, device_idx); | |
| 242 } else if (stream_type == kVideoCapture) { | |
| 243 it->requester->VideoDeviceFailed(it->label, device_idx); | |
| 244 } | |
| 245 GetDeviceManager(stream_type)->Close(capture_session_id); | |
| 246 devices->erase(device_it); | |
| 247 } else if (it->audio_devices.size() + it->video_devices.size() <= 1) { | |
| 248 // 2. Device not opened and no other devices for this request -> | |
| 249 // signal stream error and remove the request. | |
| 250 it->requester->StreamGenerationFailed(it->label); | |
| 251 requests_.erase(it); | |
| 252 } else { | |
| 253 // 3. Not opened but other devices exists for this request -> remove | |
| 254 // device from list, but don't signal an error. | |
| 255 devices->erase(device_it); | |
| 256 } | |
| 257 return; | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void MediaStreamManager::GetDevices(const std::string& label, | |
| 264 MediaStreamType stream_type) { | |
| 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 266 if (!enumeration_in_progress_[stream_type]) { | |
| 267 enumeration_in_progress_[stream_type] = true; | |
| 268 GetDeviceManager(stream_type)->EnumerateDevices(); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 void MediaStreamManager::DevicesAccepted(const std::string& label, | |
| 273 const StreamDeviceInfoArray& devices) { | |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 275 for (DeviceRequestList::iterator request_it = requests_.begin(); | |
| 276 request_it != requests_.end(); ++request_it) { | |
| 277 if (request_it->label == label) { | |
| 278 // We've found our request. | |
| 279 if (devices.empty()) { | |
| 280 // No available devices or user didn't accept device usage. | |
| 281 request_it->requester->StreamGenerationFailed(request_it->label); | |
| 282 requests_.erase(request_it); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 // Loop through all device types for this request. | |
| 287 for (StreamDeviceInfoArray::const_iterator device_it = devices.begin(); | |
| 288 device_it != devices.end(); ++device_it) { | |
| 289 StreamDeviceInfo device_info = *device_it; | |
| 290 | |
| 291 // Set in_use to false to be able to track if this device has been | |
| 292 // opened. in_use might be true if the device type can be used in more | |
| 293 // than one session. | |
| 294 device_info.in_use = false; | |
| 295 device_info.session_id = | |
| 296 GetDeviceManager(device_info.stream_type)->Open(device_info); | |
| 297 request_it->state[device_it->stream_type] = DeviceRequest::kOpening; | |
| 298 if (device_info.stream_type == kAudioCapture) { | |
| 299 request_it->audio_devices.push_back(device_info); | |
| 300 } else if (device_info.stream_type == kVideoCapture) { | |
| 301 request_it->video_devices.push_back(device_info); | |
| 302 } else { | |
| 303 DCHECK(false); | |
| 304 } | |
| 305 } | |
| 306 return; | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 void MediaStreamManager::Error(const std::string& label) { | |
| 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 313 // Erase this request and report an error. | |
| 314 for (DeviceRequestList::iterator it = requests_.begin(); | |
| 315 it != requests_.end(); ++it) { | |
| 316 if (it->label == label) { | |
| 317 // We've found our request. erase it and report error. | |
| 318 it->requester->StreamGenerationFailed(label); | |
| 319 requests_.erase(it); | |
| 320 return; | |
| 321 } | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 void MediaStreamManager::UseFakeDevice() { | |
| 326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 327 video_capture_manager_->UseFakeDevice(); | |
| 328 // TODO(mflodman) Add audio manager when available. | |
| 329 } | |
| 330 | |
| 331 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { | |
| 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 333 // Check if all devices are opened. | |
| 334 if (Requested(request.options, kAudioCapture)) { | |
| 335 for (StreamDeviceInfoArray::const_iterator it = | |
| 336 request.audio_devices.begin(); it != request.audio_devices.end(); | |
| 337 ++it) { | |
| 338 if (it->in_use == false) { | |
| 339 return false; | |
| 340 } | |
| 341 } | |
| 342 } | |
| 343 if (Requested(request.options, kVideoCapture)) { | |
| 344 for (StreamDeviceInfoArray::const_iterator it = | |
| 345 request.video_devices.begin(); it != request.video_devices.end(); | |
| 346 ++it) { | |
| 347 if (it->in_use == false) { | |
| 348 return false; | |
| 349 } | |
| 350 } | |
| 351 } | |
| 352 return true; | |
| 353 } | |
| 354 | |
| 355 // Called to get media capture device manager of specified type. | |
| 356 MediaStreamProvider* MediaStreamManager::GetDeviceManager( | |
| 357 MediaStreamType stream_type) const { | |
| 358 if (stream_type == kVideoCapture) { | |
| 359 return video_capture_manager_; | |
| 360 } else if (stream_type == kAudioCapture) { | |
| 361 // TODO(mflodman) Add support when audio input manager is available. | |
| 362 DCHECK(false); | |
| 363 return NULL; | |
| 364 } | |
| 365 DCHECK(false); | |
| 366 return NULL; | |
| 367 } | |
| 368 | |
| 369 MediaStreamManager::MediaStreamManager() | |
| 370 : video_capture_manager_(new VideoCaptureManager()), | |
| 371 enumeration_in_progress_(kNumMediaStreamTypes, false), | |
| 372 requests_(), | |
| 373 device_settings_(NULL) { | |
| 374 device_settings_ = new MediaStreamDeviceSettings(this); | |
| 375 video_capture_manager_->Register(this); | |
| 376 // TODO(mflodman) Add when audio input manager is available. | |
| 377 } | |
| 378 | |
| 379 } // namespace media_stream | |
| OLD | NEW |