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

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

Issue 34393006: Refactor MediaStreamManager to never output real device id. It now always output sourceId in the fo… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix screen capture. Created 7 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/media_stream_manager.h" 5 #include "content/browser/renderer_host/media/media_stream_manager.h"
6 6
7 #include <list> 7 #include <list>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/rand_util.h" 14 #include "base/rand_util.h"
15 #include "base/run_loop.h"
15 #include "base/threading/thread.h" 16 #include "base/threading/thread.h"
16 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 17 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
17 #include "content/browser/renderer_host/media/device_request_message_filter.h" 18 #include "content/browser/renderer_host/media/device_request_message_filter.h"
18 #include "content/browser/renderer_host/media/media_stream_requester.h" 19 #include "content/browser/renderer_host/media/media_stream_requester.h"
19 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" 20 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
20 #include "content/browser/renderer_host/media/video_capture_manager.h" 21 #include "content/browser/renderer_host/media/video_capture_manager.h"
21 #include "content/browser/renderer_host/media/web_contents_capture_util.h" 22 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
22 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/content_browser_client.h" 24 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/media_device_id.h" 25 #include "content/public/browser/media_device_id.h"
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 InitializeDeviceManagersOnIOThread(); 175 InitializeDeviceManagersOnIOThread();
175 } else { 176 } else {
176 BrowserThread::PostTask( 177 BrowserThread::PostTask(
177 BrowserThread::IO, FROM_HERE, 178 BrowserThread::IO, FROM_HERE,
178 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread, 179 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
179 base::Unretained(this))); 180 base::Unretained(this)));
180 } 181 }
181 } 182 }
182 183
183 MediaStreamManager::~MediaStreamManager() { 184 MediaStreamManager::~MediaStreamManager() {
185 DVLOG(1) << "~MediaStreamManager";
184 DCHECK(requests_.empty()); 186 DCHECK(requests_.empty());
185 DCHECK(!device_thread_.get()); 187 DCHECK(!device_thread_.get());
186 } 188 }
187 189
188 VideoCaptureManager* MediaStreamManager::video_capture_manager() { 190 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190 DCHECK(video_capture_manager_.get()); 192 DCHECK(video_capture_manager_.get());
191 return video_capture_manager_.get(); 193 return video_capture_manager_.get();
192 } 194 }
193 195
194 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { 196 AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196 DCHECK(audio_input_device_manager_.get()); 198 DCHECK(audio_input_device_manager_.get());
197 return audio_input_device_manager_.get(); 199 return audio_input_device_manager_.get();
198 } 200 }
199 201
200 std::string MediaStreamManager::MakeMediaAccessRequest( 202 std::string MediaStreamManager::MakeMediaAccessRequest(
201 int render_process_id, 203 int render_process_id,
202 int render_view_id, 204 int render_view_id,
203 int page_request_id, 205 int page_request_id,
204 const StreamOptions& options, 206 const StreamOptions& options,
205 const GURL& security_origin, 207 const GURL& security_origin,
206 const MediaRequestResponseCallback& callback) { 208 const MediaRequestResponseCallback& callback) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208 // Create a new request based on options. 210 // Create a new request based on options.
209 MediaStreamRequest stream_request( 211 MediaStreamRequest stream_request(
210 render_process_id, render_view_id, page_request_id, std::string(), 212 render_process_id, render_view_id, page_request_id,
211 security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(), 213 security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(),
212 options.audio_type, options.video_type); 214 options.audio_type, options.video_type);
213 DeviceRequest* request = new DeviceRequest(NULL, stream_request, 215 DeviceRequest* request = new DeviceRequest(NULL, stream_request,
214 render_process_id, render_view_id); 216 render_process_id, render_view_id);
215 const std::string& label = AddRequest(request); 217 const std::string& label = AddRequest(request);
216 218
217 request->callback = callback; 219 request->callback = callback;
218 220 BrowserThread::PostTask(
219 HandleRequest(label); 221 BrowserThread::IO, FROM_HERE,
220 222 base::Bind(&MediaStreamManager::HandleRequest,
223 base::Unretained(this), label));
221 return label; 224 return label;
222 } 225 }
223 226
224 std::string MediaStreamManager::GenerateStream( 227 std::string MediaStreamManager::GenerateStream(
225 MediaStreamRequester* requester, 228 MediaStreamRequester* requester,
226 int render_process_id, 229 int render_process_id,
227 int render_view_id, 230 int render_view_id,
228 int page_request_id, 231 int page_request_id,
229 const StreamOptions& options, 232 const StreamOptions& options,
230 const GURL& security_origin) { 233 const GURL& security_origin) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
232 if (CommandLine::ForCurrentProcess()->HasSwitch( 235 if (CommandLine::ForCurrentProcess()->HasSwitch(
233 switches::kUseFakeDeviceForMediaStream)) { 236 switches::kUseFakeDeviceForMediaStream)) {
234 UseFakeDevice(); 237 UseFakeDevice();
235 } 238 }
236 if (CommandLine::ForCurrentProcess()->HasSwitch( 239 if (CommandLine::ForCurrentProcess()->HasSwitch(
237 switches::kUseFakeUIForMediaStream)) { 240 switches::kUseFakeUIForMediaStream)) {
238 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>()); 241 UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
239 } 242 }
240 243
241 int target_render_process_id = render_process_id;
242 int target_render_view_id = render_view_id;
243 std::string tab_capture_device_id;
244
245 // Customize options for a WebContents based capture.
246 if (options.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
247 options.video_type == MEDIA_TAB_VIDEO_CAPTURE) {
248 // TODO(justinlin): Can't plumb audio mirroring using stream type right
249 // now, so plumbing by device_id. Will revisit once it's refactored.
250 // http://crbug.com/163100
251 tab_capture_device_id =
252 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
253 !options.video_device_id.empty() ?
254 options.video_device_id : options.audio_device_id);
255
256 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
257 tab_capture_device_id, &target_render_process_id,
258 &target_render_view_id);
259 if (!has_valid_device_id ||
260 (options.audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
261 options.audio_type != MEDIA_NO_SERVICE) ||
262 (options.video_type != MEDIA_TAB_VIDEO_CAPTURE &&
263 options.video_type != MEDIA_NO_SERVICE)) {
264 LOG(ERROR) << "Invalid request.";
265 return std::string();
266 }
267 }
268
269 std::string translated_audio_device_id;
270 std::string translated_video_device_id;
271 if (options.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
272 bool found_match = TranslateGUIDToRawId(
273 MEDIA_DEVICE_AUDIO_CAPTURE, security_origin, options.audio_device_id,
274 &translated_audio_device_id);
275 DCHECK(found_match || translated_audio_device_id.empty());
276 }
277
278 if (options.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
279 bool found_match = TranslateGUIDToRawId(
280 MEDIA_DEVICE_VIDEO_CAPTURE, security_origin, options.video_device_id,
281 &translated_video_device_id);
282 DCHECK(found_match || translated_video_device_id.empty());
283 }
284
285 if (options.video_type == MEDIA_DESKTOP_VIDEO_CAPTURE ||
286 options.audio_type == MEDIA_LOOPBACK_AUDIO_CAPTURE) {
287 // For screen capture we only support two valid combinations:
288 // (1) screen video capture only, or
289 // (2) screen video capture with loopback audio capture.
290 if (options.video_type != MEDIA_DESKTOP_VIDEO_CAPTURE ||
291 (options.audio_type != MEDIA_NO_SERVICE &&
292 options.audio_type != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
293 // TODO(sergeyu): Surface error message to the calling JS code.
294 LOG(ERROR) << "Invalid screen capture request.";
295 return std::string();
296 }
297 translated_video_device_id = options.video_device_id;
298 }
299
300 // Create a new request based on options. 244 // Create a new request based on options.
301 MediaStreamRequest stream_request( 245 MediaStreamRequest stream_request(
302 target_render_process_id, target_render_view_id, page_request_id, 246 render_process_id, render_view_id, page_request_id,
303 tab_capture_device_id, security_origin, MEDIA_GENERATE_STREAM, 247 security_origin, MEDIA_GENERATE_STREAM,
304 translated_audio_device_id, translated_video_device_id, 248 options.audio_device_id, options.video_device_id,
305 options.audio_type, options.video_type); 249 options.audio_type, options.video_type);
306 DeviceRequest* request = new DeviceRequest(requester, stream_request, 250 DeviceRequest* request = new DeviceRequest(requester, stream_request,
307 render_process_id, 251 render_process_id,
308 render_view_id); 252 render_view_id);
309 const std::string& label = AddRequest(request); 253 const std::string& label = AddRequest(request);
310 HandleRequest(label); 254
255 // Need to post a task since the requester won't have label till
256 // this function returns.
257 BrowserThread::PostTask(
258 BrowserThread::IO, FROM_HERE,
259 base::Bind(&MediaStreamManager::HandleRequest,
260 base::Unretained(this), label));
311 return label; 261 return label;
312 } 262 }
313 263
314 void MediaStreamManager::CancelRequest(const std::string& label) { 264 void MediaStreamManager::CancelRequest(const std::string& label) {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
316 266
317 DeviceRequests::iterator request_it = requests_.find(label); 267 BrowserThread::PostTask(
318 if (request_it == requests_.end()) { 268 BrowserThread::IO, FROM_HERE,
319 NOTREACHED(); 269 base::Bind(&MediaStreamManager::DoCancelRequest,
270 base::Unretained(this), label));
271 }
272
273 void MediaStreamManager::DoCancelRequest(const std::string& label) {
274 DVLOG(1) << "DoCancelRequest({label = " << label << "})";
275
276 DeviceRequest* request = FindRequest(label);
277 if (!request) {
278 // This can happen if the request completes before DoCancelRequest is
279 // executed or if a client call cancel request on a stream that has failed.
320 return; 280 return;
321 } 281 }
322 scoped_ptr<DeviceRequest> request(request_it->second);
323 RemoveRequest(request_it);
324
325 if (request->request.request_type == MEDIA_ENUMERATE_DEVICES) { 282 if (request->request.request_type == MEDIA_ENUMERATE_DEVICES) {
283 DeleteRequest(label);
326 return; 284 return;
327 } 285 }
328 286
329 // This is a request for opening one or more devices. 287 // This is a request for opening one or more devices.
330 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin(); 288 for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
331 device_it != request->devices.end(); ++device_it) { 289 device_it != request->devices.end(); ++device_it) {
332 // If we have not yet requested the device to be opened - just ignore it. 290 // If we have not yet requested the device to be opened - just ignore it.
333 if (request->state(device_it->device.type) != MEDIA_REQUEST_STATE_OPENING 291 if (request->state(device_it->device.type) != MEDIA_REQUEST_STATE_OPENING
334 && 292 &&
335 request->state(device_it->device.type) != MEDIA_REQUEST_STATE_DONE) { 293 request->state(device_it->device.type) != MEDIA_REQUEST_STATE_DONE) {
336 continue; 294 continue;
337 } 295 }
338 // Stop the opening/opened devices of the requests. 296 // Stop the opening/opened devices of the requests.
339 StopDevice(*device_it); 297 StopDevice(*device_it);
340 } 298 }
341 299
342 // Cancel the request if still pending at UI side. 300 // Cancel the request if still pending at UI side.
343 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING); 301 request->SetState(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_CLOSING);
302 DeleteRequest(label);
344 } 303 }
345 304
346 void MediaStreamManager::CancelAllRequests(int render_process_id) { 305 void MediaStreamManager::CancelAllRequests(int render_process_id) {
347 DeviceRequests::iterator request_it = requests_.begin(); 306 DeviceRequests::iterator request_it = requests_.begin();
348 while (request_it != requests_.end()) { 307 while (request_it != requests_.end()) {
349 if (request_it->second->requesting_process_id != render_process_id) { 308 if (request_it->second->requesting_process_id != render_process_id) {
350 ++request_it; 309 ++request_it;
351 continue; 310 continue;
352 } 311 }
353 312
354 std::string label = request_it->first; 313 std::string label = request_it->first;
355 ++request_it; 314 ++request_it;
356 CancelRequest(label); 315 BrowserThread::PostTask(
316 BrowserThread::IO, FROM_HERE,
317 base::Bind(&MediaStreamManager::DoCancelRequest,
318 base::Unretained(this), label));
357 } 319 }
358 } 320 }
359 321
360 void MediaStreamManager::StopStreamDevice(int render_process_id, 322 void MediaStreamManager::StopStreamDevice(int render_process_id,
361 int render_view_id, 323 int render_view_id,
362 const std::string& device_id) { 324 const std::string& device_id) {
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
364 DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id << "} " 326 DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id << "} "
365 << ", {device_id = " << device_id << "})"; 327 << ", {device_id = " << device_id << "})";
328 BrowserThread::PostTask(
329 BrowserThread::IO, FROM_HERE,
330 base::Bind(&MediaStreamManager::DoStopStreamDevice,
331 base::Unretained(this), render_process_id, render_view_id,
332 device_id));
333 }
366 334
335 void MediaStreamManager::DoStopStreamDevice(int render_process_id,
336 int render_view_id,
337 const std::string& device_id) {
367 // Find all requests for this |render_process_id| and |render_view_id| of type 338 // Find all requests for this |render_process_id| and |render_view_id| of type
368 // MEDIA_GENERATE_STREAM that has requested to use |device_id|. 339 // MEDIA_GENERATE_STREAM that has requested to use |device_id|.
369 DeviceRequests::iterator request_it = requests_.begin(); 340 DeviceRequests::iterator request_it = requests_.begin();
370 while (request_it != requests_.end()) { 341 while (request_it != requests_.end()) {
371 DeviceRequest* request = request_it->second; 342 DeviceRequest* request = request_it->second;
372 const MediaStreamRequest& ms_request = request->request; 343 const MediaStreamRequest& ms_request = request->request;
373 if (request->requesting_process_id != render_process_id || 344 if (request->requesting_process_id != render_process_id ||
374 request->requesting_view_id != render_view_id || 345 request->requesting_view_id != render_view_id ||
375 ms_request.request_type != MEDIA_GENERATE_STREAM) { 346 ms_request.request_type != MEDIA_GENERATE_STREAM) {
376 ++request_it; 347 ++request_it;
377 continue; 348 continue;
378 } 349 }
379 350
380 StreamDeviceInfoArray* devices = &request->devices; 351 StreamDeviceInfoArray* devices = &request->devices;
381 StreamDeviceInfoArray::iterator device_it = devices->begin(); 352 StreamDeviceInfoArray::iterator device_it = devices->begin();
382 while (device_it != devices->end()) { 353 while (device_it != devices->end()) {
383 MediaStreamType device_type = device_it->device.type; 354 MediaStreamType device_type = device_it->device.type;
384 if (device_it->device.id == device_id) { 355 if (device_it->device.id == device_id) {
385 if (request->state(device_type) == MEDIA_REQUEST_STATE_DONE) { 356 if (request->state(device_type) == MEDIA_REQUEST_STATE_DONE) {
386 StopDevice(*device_it); 357 StopDevice(*device_it);
387 } 358 }
388 device_it = devices->erase(device_it); 359 device_it = devices->erase(device_it);
389 } else { 360 } else {
390 ++device_it; 361 ++device_it;
391 } 362 }
392 } 363 }
393 364
394 // If this request doesn't have any active devices, remove the request. 365 // If this request doesn't have any active devices, remove the request.
395 if (devices->empty()) { 366 if (devices->empty()) {
396 DeviceRequests::iterator del_itor(request_it); 367 std::string label = request_it->first;
397 ++request_it; 368 ++request_it;
398 scoped_ptr<DeviceRequest> request(del_itor->second); 369 DeleteRequest(label);
399 RemoveRequest(del_itor);
400 } else { 370 } else {
401 ++request_it; 371 ++request_it;
402 } 372 }
403 } 373 }
404 } 374 }
405 375
406 void MediaStreamManager::StopDevice(const StreamDeviceInfo& device_info) { 376 void MediaStreamManager::StopDevice(const StreamDeviceInfo& device_info) {
407 DVLOG(1) << "StopDevice(" 377 DVLOG(1) << "StopDevice("
408 << "{device_info.session_id = " << device_info.session_id << "} " 378 << "{device_info.session_id = " << device_info.session_id << "} "
409 << "{device_id = " << device_info.device.id << "})"; 379 << "{device_id = " << device_info.device.id << "})";
(...skipping 30 matching lines...) Expand all
440 // starts monitoring devices. 410 // starts monitoring devices.
441 if (!requester) { 411 if (!requester) {
442 if (!monitoring_started_) 412 if (!monitoring_started_)
443 StartMonitoring(); 413 StartMonitoring();
444 414
445 return std::string(); 415 return std::string();
446 } 416 }
447 417
448 // Create a new request. 418 // Create a new request.
449 StreamOptions options; 419 StreamOptions options;
450 EnumerationCache* cache = NULL;
451 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) { 420 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
452 options.audio_type = type; 421 options.audio_type = type;
453 cache = &audio_enumeration_cache_;
454 } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) { 422 } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) {
455 options.video_type = type; 423 options.video_type = type;
456 cache = &video_enumeration_cache_;
457 } else { 424 } else {
458 NOTREACHED(); 425 NOTREACHED();
459 return std::string(); 426 return std::string();
460 } 427 }
461 428
462 MediaStreamRequest stream_request( 429 MediaStreamRequest stream_request(
463 render_process_id, render_view_id, page_request_id, std::string(), 430 render_process_id, render_view_id, page_request_id,
464 security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(), 431 security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(),
465 options.audio_type, options.video_type); 432 options.audio_type, options.video_type);
466 DeviceRequest* request = new DeviceRequest(requester, stream_request, 433 DeviceRequest* request = new DeviceRequest(requester, stream_request,
467 render_process_id, 434 render_process_id,
468 render_view_id); 435 render_view_id);
469 const std::string& label = AddRequest(request); 436 const std::string& label = AddRequest(request);
437 BrowserThread::PostTask(
438 BrowserThread::IO, FROM_HERE,
439 base::Bind(&MediaStreamManager::DoEnumerateDevices,
440 base::Unretained(this), label));
441
442 return label;
443 }
444
445 void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
447 DeviceRequest* request = FindRequest(label);;
448
449 MediaStreamType type;
450 EnumerationCache* cache;
451 if (request->request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
452 DCHECK(request->request.video_type == MEDIA_NO_SERVICE);
453 type = MEDIA_DEVICE_AUDIO_CAPTURE;
454 cache = &audio_enumeration_cache_;
455 } else {
456 DCHECK(request->request.video_type == MEDIA_DEVICE_VIDEO_CAPTURE);
457 type = MEDIA_DEVICE_VIDEO_CAPTURE;
458 cache = &video_enumeration_cache_;
459 }
470 460
471 if (cache->valid) { 461 if (cache->valid) {
472 // Cached device list of this type exists. Just send it out. 462 // Cached device list of this type exists. Just send it out.
473 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED); 463 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
474 464 request->devices = cache->devices;
475 // Need to post a task since the requester won't have label till 465 FinalizeEnumerateDevices(label, request);
476 // this function returns.
477 BrowserThread::PostTask(
478 BrowserThread::IO, FROM_HERE,
479 base::Bind(&MediaStreamManager::SendCachedDeviceList,
480 base::Unretained(this), cache, label));
481 } else { 466 } else {
482 StartEnumeration(request); 467 StartEnumeration(request);
483 } 468 }
484
485 return label;
486 } 469 }
487 470
488 std::string MediaStreamManager::OpenDevice( 471 std::string MediaStreamManager::OpenDevice(
489 MediaStreamRequester* requester, 472 MediaStreamRequester* requester,
490 int render_process_id, 473 int render_process_id,
491 int render_view_id, 474 int render_view_id,
492 int page_request_id, 475 int page_request_id,
493 const std::string& device_id, 476 const std::string& device_id,
494 MediaStreamType type, 477 MediaStreamType type,
495 const GURL& security_origin) { 478 const GURL& security_origin) {
496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
497 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || 480 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
498 type == MEDIA_DEVICE_VIDEO_CAPTURE); 481 type == MEDIA_DEVICE_VIDEO_CAPTURE);
499 482
500 // Create a new request. 483 // Create a new request.
501 StreamOptions options; 484 StreamOptions options;
502 if (IsAudioMediaType(type)) { 485 if (IsAudioMediaType(type)) {
503 options.audio_type = type; 486 options.audio_type = type;
504 options.audio_device_id = device_id; 487 options.audio_device_id = device_id;
505 } else if (IsVideoMediaType(type)) { 488 } else if (IsVideoMediaType(type)) {
506 options.video_type = type; 489 options.video_type = type;
507 options.video_device_id = device_id; 490 options.video_device_id = device_id;
508 } else { 491 } else {
509 NOTREACHED(); 492 NOTREACHED();
510 return std::string(); 493 return std::string();
511 } 494 }
512 495
513 MediaStreamRequest stream_request( 496 MediaStreamRequest stream_request(
514 render_process_id, render_view_id, page_request_id, std::string(), 497 render_process_id, render_view_id, page_request_id,
515 security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id, 498 security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id,
516 options.video_device_id, options.audio_type, options.video_type); 499 options.video_device_id, options.audio_type, options.video_type);
517 DeviceRequest* request = new DeviceRequest(requester, stream_request, 500 DeviceRequest* request = new DeviceRequest(requester, stream_request,
518 render_process_id, 501 render_process_id,
519 render_view_id); 502 render_view_id);
520 const std::string& label = AddRequest(request); 503 const std::string& label = AddRequest(request);
521 StartEnumeration(request); 504 BrowserThread::PostTask(
505 BrowserThread::IO, FROM_HERE,
506 base::Bind(&MediaStreamManager::HandleRequest,
507 base::Unretained(this), label));
522 508
523 return label; 509 return label;
524 } 510 }
525 511
526 void MediaStreamManager::SendCachedDeviceList(
527 EnumerationCache* cache,
528 const std::string& label) {
529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
530 if (cache->valid) {
531 DeviceRequests::iterator it = requests_.find(label);
532 if (it != requests_.end()) {
533 it->second->requester->DevicesEnumerated(label, cache->devices);
534 }
535 }
536 }
537
538 void MediaStreamManager::StartMonitoring() { 512 void MediaStreamManager::StartMonitoring() {
539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
540 if (!base::SystemMonitor::Get()) 514 if (!base::SystemMonitor::Get())
541 return; 515 return;
542 516
543 if (!monitoring_started_) { 517 if (!monitoring_started_) {
544 monitoring_started_ = true; 518 monitoring_started_ = true;
545 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); 519 base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
546 520
547 // Enumerate both the audio and video devices to cache the device lists 521 // Enumerate both the audio and video devices to cache the device lists
548 // and send them to media observer. 522 // and send them to media observer.
549 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE]; 523 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
550 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE); 524 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
551 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE]; 525 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
552 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 526 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
553 } 527 }
554 } 528 }
555 529
556 void MediaStreamManager::StopMonitoring() { 530 void MediaStreamManager::StopMonitoring() {
557 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 531 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
558 if (monitoring_started_) { 532 if (monitoring_started_) {
559 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); 533 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
560 monitoring_started_ = false; 534 monitoring_started_ = false;
561 ClearEnumerationCache(&audio_enumeration_cache_); 535 ClearEnumerationCache(&audio_enumeration_cache_);
562 ClearEnumerationCache(&video_enumeration_cache_); 536 ClearEnumerationCache(&video_enumeration_cache_);
563 } 537 }
564 } 538 }
565 539
566 bool MediaStreamManager::TranslateGUIDToRawId(MediaStreamType stream_type, 540 bool MediaStreamManager::TranslateRequestedSourceIdToDeviceId(
567 const GURL& security_origin, 541 MediaStreamRequest* request) {
568 const std::string& device_guid, 542 // If a specific device has been requested we need to find the real device id.
569 std::string* raw_device_id) { 543 if (request->audio_type == MEDIA_DEVICE_AUDIO_CAPTURE &&
tommi (sloooow) - chröme 2013/10/29 17:21:17 I'm curious - is the first check necessary here an
perkj_chrome 2013/10/30 08:59:29 I would like to. But we can not do that for screen
544 !request->requested_audio_device_id.empty()) {
545 if (!TranslateSourceIdToDeviceId(MEDIA_DEVICE_AUDIO_CAPTURE,
546 request->security_origin,
547 request->requested_audio_device_id,
548 &request->requested_audio_device_id)) {
549 // TODO(perkj): gUM should support mandatory and optional constraints.
550 // Ie - if the sourceId is optional but it does not match - gUM should
551 // not fail. For now we treat sourceId as a mandatory constraint.
552 return false;
tommi (sloooow) - chröme 2013/10/29 17:21:17 Log an error?
perkj_chrome 2013/10/30 08:59:29 Done.
553 }
554 }
555
556 if (request->video_type == MEDIA_DEVICE_VIDEO_CAPTURE &&
557 !request->requested_video_device_id.empty()) {
558 if (!TranslateSourceIdToDeviceId(MEDIA_DEVICE_VIDEO_CAPTURE,
559 request->security_origin,
560 request->requested_video_device_id,
561 &request->requested_video_device_id)) {
562 // TODO(perkj): guM should support mandatory and optional constraints.
563 // Ie - if the sourceId is optional but it does not match - guM should
564 // not fail. For now we treat sourceId as a mandatory constraint.
565 return false;
566 }
567 }
568 DVLOG(1) << "Requested audio device " << request->requested_audio_device_id;
tommi (sloooow) - chröme 2013/10/29 17:21:17 nit: consolidate into a single log stream.
perkj_chrome 2013/10/30 08:59:29 Done.
569 DVLOG(1) << "Requested video device " << request->requested_video_device_id;
570 return true;
571 }
572
573
574 bool MediaStreamManager::TranslateSourceIdToDeviceId(
575 MediaStreamType stream_type,
576 const GURL& security_origin,
577 const std::string& source_id,
578 std::string* device_id) {
570 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || 579 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
571 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); 580 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
572 if (device_guid.empty()) 581 DCHECK(!source_id.empty());
573 return false;
574 582
575 EnumerationCache* cache = 583 EnumerationCache* cache =
576 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 584 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
577 &audio_enumeration_cache_ : &video_enumeration_cache_; 585 &audio_enumeration_cache_ : &video_enumeration_cache_;
578 586
579 // If device monitoring hasn't started, the |device_guid| is not valid. 587 // If device monitoring hasn't started, the |device_guid| is not valid.
580 if (!cache->valid) 588 if (!cache->valid)
581 return false; 589 return false;
582 590
583 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin(); 591 for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
584 it != cache->devices.end(); 592 it != cache->devices.end();
585 ++it) { 593 ++it) {
586 if (content::DoesMediaDeviceIDMatchHMAC( 594 if (content::DoesMediaDeviceIDMatchHMAC(security_origin, source_id,
587 security_origin, device_guid, it->device.id)) { 595 it->device.id)) {
588 *raw_device_id = it->device.id; 596 *device_id = it->device.id;
589 return true; 597 return true;
590 } 598 }
591 } 599 }
592 return false; 600 return false;
593 } 601 }
594 602
595 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { 603 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
596 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 604 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
597 cache->valid = false; 605 cache->valid = false;
598 } 606 }
(...skipping 27 matching lines...) Expand all
626 std::string unique_label; 634 std::string unique_label;
627 do { 635 do {
628 unique_label = RandomLabel(); 636 unique_label = RandomLabel();
629 } while (requests_.find(unique_label) != requests_.end()); 637 } while (requests_.find(unique_label) != requests_.end());
630 638
631 requests_.insert(std::make_pair(unique_label, request)); 639 requests_.insert(std::make_pair(unique_label, request));
632 640
633 return unique_label; 641 return unique_label;
634 } 642 }
635 643
636 void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) { 644 MediaStreamManager::DeviceRequest*
645 MediaStreamManager::FindRequest(const std::string& label) {
646 DeviceRequests::iterator request_it = requests_.find(label);
647 if (request_it == requests_.end()) {
tommi (sloooow) - chröme 2013/10/29 17:21:17 nit: no {} could also just do: return request_it =
perkj_chrome 2013/10/30 08:59:29 thanks
648 return NULL;
649 }
650 return request_it->second;
651 }
652
653 void MediaStreamManager::DeleteRequest(const std::string& label) {
654 DeviceRequests::iterator it = requests_.find(label);
655 scoped_ptr<DeviceRequest> request(it->second);
637 requests_.erase(it); 656 requests_.erase(it);
638 } 657 }
639 658
640 void MediaStreamManager::PostRequestToUI(const std::string& label) { 659 void MediaStreamManager::PostRequestToUI(const std::string& label) {
641 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
642 DeviceRequest* request = requests_[label]; 661 DeviceRequest* request = FindRequest(label);
643 662
644 if (use_fake_ui_) { 663 if (use_fake_ui_) {
645 if (!fake_ui_) 664 if (!fake_ui_)
646 fake_ui_.reset(new FakeMediaStreamUIProxy()); 665 fake_ui_.reset(new FakeMediaStreamUIProxy());
647 666
648 MediaStreamDevices devices; 667 MediaStreamDevices devices;
649 if (audio_enumeration_cache_.valid) { 668 if (audio_enumeration_cache_.valid) {
650 for (StreamDeviceInfoArray::const_iterator it = 669 for (StreamDeviceInfoArray::const_iterator it =
651 audio_enumeration_cache_.devices.begin(); 670 audio_enumeration_cache_.devices.begin();
652 it != audio_enumeration_cache_.devices.end(); ++it) { 671 it != audio_enumeration_cache_.devices.end(); ++it) {
(...skipping 16 matching lines...) Expand all
669 } 688 }
670 689
671 request->ui_proxy->RequestAccess( 690 request->ui_proxy->RequestAccess(
672 request->request, 691 request->request,
673 base::Bind(&MediaStreamManager::HandleAccessRequestResponse, 692 base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
674 base::Unretained(this), label)); 693 base::Unretained(this), label));
675 } 694 }
676 695
677 void MediaStreamManager::HandleRequest(const std::string& label) { 696 void MediaStreamManager::HandleRequest(const std::string& label) {
678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
679 DeviceRequest* request = requests_[label]; 698 DeviceRequest* request = FindRequest(label);
680 699
681 const MediaStreamType audio_type = request->request.audio_type; 700 const MediaStreamType audio_type = request->request.audio_type;
682 const MediaStreamType video_type = request->request.video_type; 701 const MediaStreamType video_type = request->request.video_type;
683 702
684 bool is_web_contents_capture = 703 bool is_web_contents_capture =
685 audio_type == MEDIA_TAB_AUDIO_CAPTURE || 704 audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
686 video_type == MEDIA_TAB_VIDEO_CAPTURE; 705 video_type == MEDIA_TAB_VIDEO_CAPTURE;
706 if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
707 FinalizeRequestFailed(label, request);
708 return;
709 }
687 710
688 bool is_screen_capture = 711 bool is_screen_capture =
689 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE; 712 video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
713 if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
714 FinalizeRequestFailed(label, request);
715 return;
716 }
690 717
691 if (!is_web_contents_capture && 718 if (!is_web_contents_capture &&
692 !is_screen_capture && 719 !is_screen_capture &&
693 ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) || 720 ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) ||
694 (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) { 721 (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) {
695 // Enumerate the devices if there is no valid device lists to be used. 722 // Enumerate the devices if there is no valid device lists to be used.
696 StartEnumeration(request); 723 StartEnumeration(request);
697 return; 724 return;
698 } 725 }
699 726
727 // If a specific device has been requested we need to find the real device id.
728 if (!TranslateRequestedSourceIdToDeviceId(&request->request)) {
729 FinalizeRequestFailed(label, request);
730 return;
731 }
732
700 // No need to do new device enumerations, post the request to UI 733 // No need to do new device enumerations, post the request to UI
701 // immediately. 734 // immediately.
702 if (IsAudioMediaType(audio_type)) 735 if (IsAudioMediaType(audio_type))
703 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 736 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
704 if (IsVideoMediaType(video_type)) 737 if (IsVideoMediaType(video_type))
705 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 738 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
706 739
707 PostRequestToUI(label); 740 PostRequestToUI(label);
708 } 741 }
709 742
743 bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
744 DCHECK(request->request.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
745 request->request.video_type == MEDIA_TAB_VIDEO_CAPTURE);
746
747 MediaStreamRequest* ms_request = &request->request;
748 // Customize options for a WebContents based capture.
749 int target_render_process_id = 0;
750 int target_render_view_id = 0;
751
752 // TODO(justinlin): Can't plumb audio mirroring using stream type right
753 // now, so plumbing by device_id. Will revisit once it's refactored.
754 // http://crbug.com/163100
755 std::string tab_capture_device_id =
756 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
757 !ms_request->requested_video_device_id.empty() ?
758 ms_request->requested_video_device_id :
759 ms_request->requested_audio_device_id);
760
761 bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
762 tab_capture_device_id, &target_render_process_id,
763 &target_render_view_id);
764 if (!has_valid_device_id ||
765 (ms_request->audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
766 ms_request->audio_type != MEDIA_NO_SERVICE) ||
767 (ms_request->video_type != MEDIA_TAB_VIDEO_CAPTURE &&
768 ms_request->video_type != MEDIA_NO_SERVICE)) {
769 return false;
770 }
771 ms_request->tab_capture_device_id = tab_capture_device_id;
772 ms_request->render_process_id = target_render_process_id;
773 ms_request->render_view_id = target_render_view_id;
774 DVLOG(3) << "SetupTabCaptureRequest "
775 << ", {tab_capture_device_id = " << tab_capture_device_id << "}"
776 << ", {target_render_process_id = " << target_render_process_id
777 << "}"
778 << ", {target_render_view_id = " << target_render_view_id << "}";
779 return true;
780 }
781
782 bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
783 DCHECK(request->request.audio_type == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
784 request->request.video_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
785 const MediaStreamRequest& ms_request = request->request;
786
787 // For screen capture we only support two valid combinations:
788 // (1) screen video capture only, or
789 // (2) screen video capture with loopback audio capture.
790 if (ms_request.video_type != MEDIA_DESKTOP_VIDEO_CAPTURE ||
791 (ms_request.audio_type != MEDIA_NO_SERVICE &&
792 ms_request.audio_type != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
793 // TODO(sergeyu): Surface error message to the calling JS code.
794 LOG(ERROR) << "Invalid screen capture request.";
795 return false;
796 }
797 return true;
798 }
799
800 const StreamDeviceInfo* MediaStreamManager::FindRequestedDeviceInfoForTest(
801 const std::string& source_id,
802 int render_process_id,
803 int render_view_id,
804 MediaStreamRequestType type) {
tommi (sloooow) - chröme 2013/10/29 17:21:17 Do you need to DCHECK that you're on the correct t
perkj_chrome 2013/10/30 08:59:29 I don't think I need to but it doesn't hurt.
805 for (DeviceRequests::const_iterator it = requests_.begin();
806 it != requests_.end() ; ++it) {
807 const DeviceRequest* request = it->second;
808 if (request->request.render_process_id == render_process_id &&
809 request->request.render_view_id == render_view_id &&
810 request->request.request_type == type) {
811 for (StreamDeviceInfoArray::const_iterator device_it =
812 request->devices.begin();
813 device_it != request->devices.end(); ++device_it) {
814 if (source_id == device_it->device.id) {
815 return &*device_it;
816 }
817 }
818 }
819 }
820 return NULL;
821 }
822
823 void MediaStreamManager::WillDestroyCurrentMessageLoopForTest() {
tommi (sloooow) - chröme 2013/10/29 17:21:17 why do you need to implement this here? seems lik
perkj_chrome 2013/10/30 08:59:29 except that we discussed that we should make WillD
824 base::RunLoop().RunUntilIdle();
825 WillDestroyCurrentMessageLoop();
826 }
827
710 bool MediaStreamManager::FindExistingRequestedDeviceInfo( 828 bool MediaStreamManager::FindExistingRequestedDeviceInfo(
711 int render_process_id, 829 int render_process_id,
712 int render_view_id, 830 int render_view_id,
831 const GURL& security_origin,
713 MediaStreamRequestType type, 832 MediaStreamRequestType type,
714 const std::string& device_id, 833 const std::string& device_id,
834 MediaStreamType device_type,
715 StreamDeviceInfo* device_info, 835 StreamDeviceInfo* device_info,
716 MediaRequestState* request_state) const { 836 MediaRequestState* request_state) const {
717 DCHECK(device_info); 837 DCHECK(device_info);
718 DCHECK(request_state); 838 DCHECK(request_state);
839
840 std::string source_id = content::GetHMACForMediaDeviceID(
841 security_origin,
842 device_id);
843
719 for (DeviceRequests::const_iterator it = requests_.begin(); 844 for (DeviceRequests::const_iterator it = requests_.begin();
720 it != requests_.end() ; ++it) { 845 it != requests_.end() ; ++it) {
721 const DeviceRequest* request = it->second; 846 const DeviceRequest* request = it->second;
722 if (request->requesting_process_id ==render_process_id && 847 if (request->requesting_process_id == render_process_id &&
723 request->requesting_view_id == render_view_id && 848 request->requesting_view_id == render_view_id &&
724 request->request.request_type == type) { 849 request->request.request_type == type) {
725 for (StreamDeviceInfoArray::const_iterator device_it = 850 for (StreamDeviceInfoArray::const_iterator device_it =
726 request->devices.begin(); 851 request->devices.begin();
727 device_it != request->devices.end(); ++device_it) { 852 device_it != request->devices.end(); ++device_it) {
728 if (device_it->device.id == device_id) { 853 if (device_it->device.id == source_id &&
854 device_it->device.type == device_type) {
729 *device_info = *device_it; 855 *device_info = *device_it;
730 *request_state = request->state(device_it->device.type); 856 *request_state = request->state(device_it->device.type);
731 return true; 857 return true;
732 } 858 }
733 } 859 }
734 } 860 }
735 } 861 }
736 return false; 862 return false;
737 } 863 }
738 864
865 void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
866 DeviceRequest* request) {
867 const StreamDeviceInfoArray& requested_devices = request->devices;
868
869 // Partition the array of devices into audio vs video.
870 StreamDeviceInfoArray audio_devices, video_devices;
871 for (StreamDeviceInfoArray::const_iterator device_it =
872 requested_devices.begin();
tommi (sloooow) - chröme 2013/10/29 17:21:17 nit: indent
perkj_chrome 2013/10/30 08:59:29 Done.
873 device_it != requested_devices.end(); ++device_it) {
874 if (IsAudioMediaType(device_it->device.type)) {
875 audio_devices.push_back(*device_it);
876 } else if (IsVideoMediaType(device_it->device.type)) {
877 video_devices.push_back(*device_it);
878 } else {
879 NOTREACHED();
880 }
881 }
882
883 request->requester->StreamGenerated(label, audio_devices, video_devices);
884 }
885
886 void MediaStreamManager::FinalizeRequestFailed(
887 const std::string& label,
888 DeviceRequest* request) {
889 if (request->requester)
890 request->requester->StreamGenerationFailed(label);
891
892 if (request->request.request_type == MEDIA_DEVICE_ACCESS &&
893 !request->callback.is_null()) {
894 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
895 }
896
897 DeleteRequest(label);
898 }
899
900 void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
901 DeviceRequest* request) {
902 const StreamDeviceInfoArray& requested_devices = request->devices;
903 request->requester->DeviceOpened(label, requested_devices.front());
904 }
905
906 void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
907 DeviceRequest* request) {
908 for (StreamDeviceInfoArray::iterator it = request->devices.begin();
909 it != request->devices.end(); ++it) {
910 it->device.id = content::GetHMACForMediaDeviceID(
911 request->request.security_origin, it->device.id);
912 }
913 request->requester->DevicesEnumerated(label, request->devices);
914 }
915
916 void MediaStreamManager::FinalizeMediaAccessRequest(
917 const std::string& label,
918 DeviceRequest* request,
919 const MediaStreamDevices& devices) {
920 if (!request->callback.is_null())
921 request->callback.Run(devices, request->ui_proxy.Pass());
922
923 // Delete the request since it is done.
924 DeleteRequest(label);
925 }
926
739 void MediaStreamManager::InitializeDeviceManagersOnIOThread() { 927 void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
740 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 928 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
741 if (device_thread_) 929 if (device_thread_)
742 return; 930 return;
743 931
744 device_thread_.reset(new base::Thread("MediaStreamDeviceThread")); 932 device_thread_.reset(new base::Thread("MediaStreamDeviceThread"));
745 #if defined(OS_WIN) 933 #if defined(OS_WIN)
746 device_thread_->init_com_with_mta(true); 934 device_thread_->init_com_with_mta(true);
747 #endif 935 #endif
748 CHECK(device_thread_->Start()); 936 CHECK(device_thread_->Start());
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE); 971 request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_DONE);
784 972
785 if (IsAudioMediaType(device_it->device.type)) { 973 if (IsAudioMediaType(device_it->device.type)) {
786 // Store the native audio parameters in the device struct. 974 // Store the native audio parameters in the device struct.
787 // TODO(xians): Handle the tab capture sample rate/channel layout 975 // TODO(xians): Handle the tab capture sample rate/channel layout
788 // in AudioInputDeviceManager::Open(). 976 // in AudioInputDeviceManager::Open().
789 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) { 977 if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
790 const StreamDeviceInfo* info = 978 const StreamDeviceInfo* info =
791 audio_input_device_manager_->GetOpenedDeviceInfoById( 979 audio_input_device_manager_->GetOpenedDeviceInfoById(
792 device_it->session_id); 980 device_it->session_id);
793 DCHECK_EQ(info->device.id, device_it->device.id);
794 device_it->device.input = info->device.input; 981 device_it->device.input = info->device.input;
795 device_it->device.matched_output = info->device.matched_output; 982 device_it->device.matched_output = info->device.matched_output;
796 } 983 }
797 } 984 }
798 if (RequestDone(*request)) 985 if (RequestDone(*request))
799 HandleRequestDone(label, request); 986 HandleRequestDone(label, request);
800 break; 987 break;
801 } 988 }
802 } 989 }
803 } 990 }
804 } 991 }
805 992
806 void MediaStreamManager::HandleRequestDone(const std::string& label, 993 void MediaStreamManager::HandleRequestDone(const std::string& label,
807 DeviceRequest* request) { 994 DeviceRequest* request) {
808 DCHECK(RequestDone(*request)); 995 DCHECK(RequestDone(*request));
809 DVLOG(1) << "HandleRequestDone(" 996 DVLOG(1) << "HandleRequestDone("
810 << ", {label = " << label << "})"; 997 << ", {label = " << label << "})";
811 998
812 const StreamDeviceInfoArray& requested_devices = request->devices;
813 switch (request->request.request_type) { 999 switch (request->request.request_type) {
814 case MEDIA_OPEN_DEVICE: 1000 case MEDIA_OPEN_DEVICE:
815 request->requester->DeviceOpened(label, requested_devices.front()); 1001 FinalizeOpenDevice(label, request);
816 break; 1002 break;
817 case MEDIA_GENERATE_STREAM: { 1003 case MEDIA_GENERATE_STREAM: {
818 // Partition the array of devices into audio vs video. 1004 FinalizeGenerateStream(label, request);
819 StreamDeviceInfoArray audio_devices, video_devices;
820 for (StreamDeviceInfoArray::const_iterator device_it =
821 requested_devices.begin();
822 device_it != requested_devices.end(); ++device_it) {
823 if (IsAudioMediaType(device_it->device.type)) {
824 audio_devices.push_back(*device_it);
825 } else if (IsVideoMediaType(device_it->device.type)) {
826 video_devices.push_back(*device_it);
827 } else {
828 NOTREACHED();
829 }
830 }
831
832 request->requester->StreamGenerated(label, audio_devices, video_devices);
833 break; 1005 break;
834 } 1006 }
835 default: 1007 default:
836 NOTREACHED(); 1008 NOTREACHED();
837 break; 1009 break;
838 } 1010 }
839 1011
840 if (request->ui_proxy.get()) { 1012 if (request->ui_proxy.get()) {
841 request->ui_proxy->OnStarted( 1013 request->ui_proxy->OnStarted(
842 base::Bind(&MediaStreamManager::StopStreamFromUI, 1014 base::Bind(&MediaStreamManager::StopStreamFromUI,
843 base::Unretained(this), label)); 1015 base::Unretained(this), label));
844 } 1016 }
845 } 1017 }
846 1018
847 void MediaStreamManager::Closed(MediaStreamType stream_type, 1019 void MediaStreamManager::Closed(MediaStreamType stream_type,
848 int capture_session_id) { 1020 int capture_session_id) {
849 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1021 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
850 } 1022 }
851 1023
852 void MediaStreamManager::DevicesEnumerated( 1024 void MediaStreamManager::DevicesEnumerated(
853 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { 1025 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
854 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1026 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1027 DVLOG(1) << "DevicesEnumerated";
855 1028
856 // Only cache the device list when the device list has been changed. 1029 // Only cache the device list when the device list has been changed.
857 bool need_update_clients = false; 1030 bool need_update_clients = false;
858 EnumerationCache* cache = 1031 EnumerationCache* cache =
859 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? 1032 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
860 &audio_enumeration_cache_ : &video_enumeration_cache_; 1033 &audio_enumeration_cache_ : &video_enumeration_cache_;
861 if (!cache->valid || 1034 if (!cache->valid ||
862 devices.size() != cache->devices.size() || 1035 devices.size() != cache->devices.size() ||
863 !std::equal(devices.begin(), devices.end(), cache->devices.begin(), 1036 !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
864 StreamDeviceInfo::IsEqual)) { 1037 StreamDeviceInfo::IsEqual)) {
(...skipping 14 matching lines...) Expand all
879 ++it) { 1052 ++it) {
880 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && 1053 if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
881 Requested(it->second->request, stream_type)) { 1054 Requested(it->second->request, stream_type)) {
882 if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES) 1055 if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES)
883 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); 1056 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
884 label_list.push_back(it->first); 1057 label_list.push_back(it->first);
885 } 1058 }
886 } 1059 }
887 for (std::list<std::string>::iterator it = label_list.begin(); 1060 for (std::list<std::string>::iterator it = label_list.begin();
888 it != label_list.end(); ++it) { 1061 it != label_list.end(); ++it) {
889 DeviceRequest* request = requests_[*it]; 1062 DeviceRequest* request = FindRequest(*it);
890 switch (request->request.request_type) { 1063 switch (request->request.request_type) {
891 case MEDIA_ENUMERATE_DEVICES: 1064 case MEDIA_ENUMERATE_DEVICES:
892 if (need_update_clients && request->requester) 1065 if (need_update_clients && request->requester) {
893 request->requester->DevicesEnumerated(*it, devices); 1066 request->devices = devices;
1067 FinalizeEnumerateDevices(*it, request);
1068 }
894 break; 1069 break;
895 default: 1070 default:
896 if (request->state(request->request.audio_type) == 1071 if (request->state(request->request.audio_type) ==
897 MEDIA_REQUEST_STATE_REQUESTED || 1072 MEDIA_REQUEST_STATE_REQUESTED ||
898 request->state(request->request.video_type) == 1073 request->state(request->request.video_type) ==
899 MEDIA_REQUEST_STATE_REQUESTED) { 1074 MEDIA_REQUEST_STATE_REQUESTED) {
900 // We are doing enumeration for other type of media, wait until it is 1075 // We are doing enumeration for other type of media, wait until it is
901 // all done before posting the request to UI because UI needs 1076 // all done before posting the request to UI because UI needs
902 // the device lists to handle the request. 1077 // the device lists to handle the request.
903 break; 1078 break;
904 } 1079 }
905 1080
906 // Post the request to UI for permission approval. 1081 // Continue to handle the request.
907 PostRequestToUI(*it); 1082 HandleRequest(*it);
908 break; 1083 break;
909 } 1084 }
910 } 1085 }
911 label_list.clear(); 1086 label_list.clear();
912 --active_enumeration_ref_count_[stream_type]; 1087 --active_enumeration_ref_count_[stream_type];
913 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); 1088 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
914 } 1089 }
915 1090
916 void MediaStreamManager::Error(MediaStreamType stream_type,
917 int capture_session_id,
918 MediaStreamProviderError error) {
919 // Find the device for the error call.
920 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
921 DVLOG(1) << "Error("
922 << "{stream_type = " << stream_type << "} ,"
923 << "{capture_session_id = " << capture_session_id << "})";
924
925
926 for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
927 ++it) {
928 StreamDeviceInfoArray& devices = it->second->devices;
929
930 // TODO(miu): BUG. It's possible for the audio (or video) device array in
931 // the "requester" to become out-of-sync with the order of devices we have
932 // here. See http://crbug.com/147650
933 int audio_device_idx = -1;
934 int video_device_idx = -1;
935 for (StreamDeviceInfoArray::iterator device_it = devices.begin();
936 device_it != devices.end(); ++device_it) {
937 if (IsAudioMediaType(device_it->device.type)) {
938 ++audio_device_idx;
939 } else if (IsVideoMediaType(device_it->device.type)) {
940 ++video_device_idx;
941 } else {
942 NOTREACHED();
943 continue;
944 }
945 if (device_it->device.type != stream_type ||
946 device_it->session_id != capture_session_id) {
947 continue;
948 }
949 // We've found the failing device. Find the error case:
950 // An error should only be reported to the MediaStreamManager if
951 // the request has not been fulfilled yet.
952 DCHECK(it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE);
953 if (it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE) {
954 // Request is not done, devices are not opened in this case.
955 if (devices.size() <= 1) {
956 scoped_ptr<DeviceRequest> request(it->second);
957 // 1. Device not opened and no other devices for this request ->
958 // signal stream error and remove the request.
959 if (request->requester)
960 request->requester->StreamGenerationFailed(it->first);
961
962 RemoveRequest(it);
963 } else {
964 // 2. Not opened but other devices exists for this request -> remove
965 // device from list, but don't signal an error.
966 devices.erase(device_it); // NOTE: This invalidates device_it!
967 it->second->SetState(stream_type, MEDIA_REQUEST_STATE_ERROR);
968 DVLOG(1) << "Error("
969 << ", {capture_session_id = " << capture_session_id << "})";
970 }
971 }
972 if (RequestDone(*it->second))
973 HandleRequestDone(it->first, it->second);
974 break;
975 }
976 }
977 }
978
979 void MediaStreamManager::HandleAccessRequestResponse( 1091 void MediaStreamManager::HandleAccessRequestResponse(
980 const std::string& label, 1092 const std::string& label,
981 const MediaStreamDevices& devices) { 1093 const MediaStreamDevices& devices) {
982 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1094 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
983 DVLOG(1) << "HandleAccessRequestResponse(" 1095 DVLOG(1) << "HandleAccessRequestResponse("
984 << ", {label = " << label << "})"; 1096 << ", {label = " << label << "})";
985 1097
986 DeviceRequests::iterator request_it = requests_.find(label); 1098 DeviceRequest* request = FindRequest(label);
987 if (request_it == requests_.end()) { 1099 if (!request) {
1100 // The request has been canceled before the UI returns.
1101 return;
1102 }
1103
1104 if (request->request.request_type == MEDIA_DEVICE_ACCESS) {
1105 FinalizeMediaAccessRequest(label, request, devices);
988 return; 1106 return;
989 } 1107 }
990 1108
991 // Handle the case when the request was denied. 1109 // Handle the case when the request was denied.
992 if (devices.empty()) { 1110 if (devices.empty()) {
993 // Notify the users about the request result. 1111 FinalizeRequestFailed(label, request);
994 scoped_ptr<DeviceRequest> request(request_it->second);
995 if (request->requester)
996 request->requester->StreamGenerationFailed(label);
997
998 if (request->request.request_type == MEDIA_DEVICE_ACCESS &&
999 !request->callback.is_null()) {
1000 request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
1001 }
1002
1003 RemoveRequest(request_it);
1004 return;
1005 }
1006
1007 if (request_it->second->request.request_type == MEDIA_DEVICE_ACCESS) {
1008 scoped_ptr<DeviceRequest> request(request_it->second);
1009 if (!request->callback.is_null())
1010 request->callback.Run(devices, request->ui_proxy.Pass());
1011
1012 // Delete the request since it is done.
1013 RemoveRequest(request_it);
1014 return; 1112 return;
1015 } 1113 }
1016 1114
1017 // Process all newly-accepted devices for this request. 1115 // Process all newly-accepted devices for this request.
1018 DeviceRequest* request = request_it->second;
1019 bool found_audio = false; 1116 bool found_audio = false;
1020 bool found_video = false; 1117 bool found_video = false;
1021 for (MediaStreamDevices::const_iterator device_it = devices.begin(); 1118 for (MediaStreamDevices::const_iterator device_it = devices.begin();
1022 device_it != devices.end(); ++device_it) { 1119 device_it != devices.end(); ++device_it) {
1023 StreamDeviceInfo device_info; 1120 StreamDeviceInfo device_info;
1024 device_info.device = *device_it; 1121 device_info.device = *device_it;
1025 1122
1026 // TODO(justinlin): Nicer way to do this? 1123 // TODO(justinlin): Nicer way to do this?
1027 // Re-append the device's id since we lost it when posting request to UI. 1124 // Re-append the device's id since we lost it when posting request to UI.
1028 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE || 1125 if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
(...skipping 20 matching lines...) Expand all
1049 if (device_info.device.type == request->request.audio_type) { 1146 if (device_info.device.type == request->request.audio_type) {
1050 found_audio = true; 1147 found_audio = true;
1051 } else if (device_info.device.type == request->request.video_type) { 1148 } else if (device_info.device.type == request->request.video_type) {
1052 found_video = true; 1149 found_video = true;
1053 } 1150 }
1054 1151
1055 // If this is request for a new MediaStream, a device is only opened once 1152 // If this is request for a new MediaStream, a device is only opened once
1056 // per render view. This is so that the permission to use a device can be 1153 // per render view. This is so that the permission to use a device can be
1057 // revoked by a single call to StopStreamDevice regardless of how many 1154 // revoked by a single call to StopStreamDevice regardless of how many
1058 // MediaStreams it is being used in. 1155 // MediaStreams it is being used in.
1059
1060 if (request->request.request_type == MEDIA_GENERATE_STREAM) { 1156 if (request->request.request_type == MEDIA_GENERATE_STREAM) {
1061 MediaRequestState state; 1157 MediaRequestState state;
1062 if (FindExistingRequestedDeviceInfo(request->requesting_process_id, 1158 if (FindExistingRequestedDeviceInfo(request->requesting_process_id,
1063 request->requesting_view_id, 1159 request->requesting_view_id,
1160 request->request.security_origin,
1064 request->request.request_type, 1161 request->request.request_type,
1065 device_it->id, 1162 device_info.device.id,
1163 device_info.device.type,
1066 &device_info, 1164 &device_info,
1067 &state)) { 1165 &state)) {
1068 request->devices.push_back(device_info); 1166 request->devices.push_back(device_info);
1069 request->SetState(device_info.device.type, state); 1167 request->SetState(device_info.device.type, state);
1070 DVLOG(1) << "HandleAccessRequestResponse - device already opened " 1168 DVLOG(1) << "HandleAccessRequestResponse - device already opened "
1071 << ", {label = " << label << "}" 1169 << ", {label = " << label << "}"
1072 << ", device_id = " << device_it->id << "}"; 1170 << ", device_id = " << device_it->id << "}";
1073 continue; 1171 continue;
1074 } 1172 }
1075 } 1173 }
1076 device_info.session_id = 1174 device_info.session_id =
1077 GetDeviceManager(device_info.device.type)->Open(device_info); 1175 GetDeviceManager(device_info.device.type)->Open(device_info);
1176 device_info.device.id = content::GetHMACForMediaDeviceID(
tommi (sloooow) - chröme 2013/10/30 14:47:30 as discussed do the same checks as are done above
perkj_chrome 2013/10/30 16:57:08 Done.
1177 request->request.security_origin,
1178 device_info.device.id);
1078 request->devices.push_back(device_info); 1179 request->devices.push_back(device_info);
1180
1079 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING); 1181 request->SetState(device_info.device.type, MEDIA_REQUEST_STATE_OPENING);
1080 DVLOG(1) << "HandleAccessRequestResponse - opening device " 1182 DVLOG(1) << "HandleAccessRequestResponse - opening device "
1081 << ", {label = " << label << "}" 1183 << ", {label = " << label << "}"
1082 << ", {device_id = " << device_it->id << "}" 1184 << ", {device_id = " << device_info.device.id << "}"
1083 << ", {session_id = " << device_info.session_id << "}"; 1185 << ", {session_id = " << device_info.session_id << "}";
1084 } 1186 }
1085 1187
1086 // Check whether we've received all stream types requested. 1188 // Check whether we've received all stream types requested.
1087 if (!found_audio && IsAudioMediaType(request->request.audio_type)) { 1189 if (!found_audio && IsAudioMediaType(request->request.audio_type)) {
1088 request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR); 1190 request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR);
1089 DVLOG(1) << "Set no audio found label " << label; 1191 DVLOG(1) << "Set no audio found label " << label;
1090 } 1192 }
1091 1193
1092 if (!found_video && IsVideoMediaType(request->request.video_type)) 1194 if (!found_video && IsVideoMediaType(request->request.video_type))
1093 request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR); 1195 request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR);
1094 1196
1095 if (RequestDone(*request)) 1197 if (RequestDone(*request))
1096 HandleRequestDone(label, request); 1198 HandleRequestDone(label, request);
1097 } 1199 }
1098 1200
1099 void MediaStreamManager::StopStreamFromUI(const std::string& label) { 1201 void MediaStreamManager::StopStreamFromUI(const std::string& label) {
1100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1101 1203
1102 DeviceRequests::iterator it = requests_.find(label); 1204 DeviceRequest* request = FindRequest(label);
1103 if (it == requests_.end()) 1205 if (!request)
1104 return; 1206 return;
1105 1207
1106 // Notify renderers that the stream has been stopped. 1208 // Notify renderers that the stream has been stopped.
1107 if (it->second->requester) 1209 if (request->requester)
tommi (sloooow) - chröme 2013/10/29 17:21:17 {}
perkj_chrome 2013/10/30 08:59:29 Done.
1108 it->second->requester->StopGeneratedStream( 1210 request->requester->StopGeneratedStream(
1109 it->second->request.render_view_id, 1211 request->request.render_view_id,
1110 label); 1212 label);
1111 1213
1112 CancelRequest(label); 1214 CancelRequest(label);
1113 } 1215 }
1114 1216
1115 void MediaStreamManager::UseFakeDevice() { 1217 void MediaStreamManager::UseFakeDevice() {
1116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1117 video_capture_manager()->UseFakeDevice(); 1219 video_capture_manager()->UseFakeDevice();
1118 audio_input_device_manager()->UseFakeDevice(); 1220 audio_input_device_manager()->UseFakeDevice();
1119 } 1221 }
1120 1222
1121 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) { 1223 void MediaStreamManager::UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
1122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1123 use_fake_ui_ = true; 1225 use_fake_ui_ = true;
1124 fake_ui_ = fake_ui.Pass(); 1226 fake_ui_ = fake_ui.Pass();
1125 } 1227 }
1126 1228
1127 void MediaStreamManager::WillDestroyCurrentMessageLoop() { 1229 void MediaStreamManager::WillDestroyCurrentMessageLoop() {
1230 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
1128 DCHECK_EQ(base::MessageLoop::current(), io_loop_); 1231 DCHECK_EQ(base::MessageLoop::current(), io_loop_);
1129 DCHECK(requests_.empty()); 1232 DCHECK(requests_.empty());
1130 if (device_thread_) { 1233 if (device_thread_) {
1131 StopMonitoring(); 1234 StopMonitoring();
1132 1235
1133 video_capture_manager_->Unregister(); 1236 video_capture_manager_->Unregister();
1134 audio_input_device_manager_->Unregister(); 1237 audio_input_device_manager_->Unregister();
1135 device_thread_.reset(); 1238 device_thread_.reset();
1136 } 1239 }
1137 1240
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1219 } 1322 }
1220 1323
1221 // Always do enumeration even though some enumeration is in progress, 1324 // Always do enumeration even though some enumeration is in progress,
1222 // because those enumeration commands could be sent before these devices 1325 // because those enumeration commands could be sent before these devices
1223 // change. 1326 // change.
1224 ++active_enumeration_ref_count_[stream_type]; 1327 ++active_enumeration_ref_count_[stream_type];
1225 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); 1328 GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1226 } 1329 }
1227 1330
1228 } // namespace content 1331 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698