media_stream_manager.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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
3// found in the LICENSE file.
4
5#include "content/browser/renderer_host/media/media_stream_manager.h"
6
7#include <list>
8
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "base/compiler_specific.h"
12#include "base/logging.h"
13#include "base/rand_util.h"
14#include "base/threading/thread.h"
15#include "content/browser/renderer_host/media/audio_input_device_manager.h"
16#include "content/browser/renderer_host/media/media_stream_requester.h"
17#include "content/browser/renderer_host/media/media_stream_ui_controller.h"
18#include "content/browser/renderer_host/media/video_capture_manager.h"
19#include "content/browser/renderer_host/media/web_contents_capture_util.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/content_browser_client.h"
22#include "content/public/browser/media_observer.h"
23#include "content/public/browser/media_request_state.h"
24#include "content/public/common/content_switches.h"
25#include "content/public/common/media_stream_request.h"
26#include "googleurl/src/gurl.h"
27#include "media/audio/audio_manager_base.h"
28#include "media/audio/audio_parameters.h"
29#include "media/base/channel_layout.h"
30
31#if defined(OS_WIN)
32#include "base/win/scoped_com_initializer.h"
33#endif
34
35namespace content {
36
37// Creates a random label used to identify requests.
38static std::string RandomLabel() {
39  // An earlier PeerConnection spec,
40  // http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
41  // MediaStream::label alphabet as containing 36 characters from
42  // range: U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to U+002E,
43  // U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E.
44  // Here we use a safe subset.
45  static const char kAlphabet[] = "0123456789"
46      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
47
48  std::string label(36, ' ');
49  for (size_t i = 0; i < label.size(); ++i) {
50    int random_char = base::RandGenerator(sizeof(kAlphabet) - 1);
51    label[i] = kAlphabet[random_char];
52  }
53  return label;
54}
55
56// Helper to verify if a media stream type is part of options or not.
57static bool Requested(const StreamOptions& options,
58                      MediaStreamType stream_type) {
59  return (options.audio_type == stream_type ||
60          options.video_type == stream_type);
61}
62
63// TODO(xians): Merge DeviceRequest with MediaStreamRequest.
64class MediaStreamManager::DeviceRequest {
65 public:
66  DeviceRequest()
67      : requester(NULL),
68        type(MEDIA_GENERATE_STREAM),
69        render_process_id(-1),
70        render_view_id(-1),
71        state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) {
72  }
73
74  DeviceRequest(MediaStreamRequester* requester,
75                const StreamOptions& request_options,
76                MediaStreamRequestType request_type,
77                int render_process_id,
78                int render_view_id,
79                const GURL& request_security_origin,
80                const std::string& requested_device_id)
81      : requester(requester),
82        options(request_options),
83        type(request_type),
84        render_process_id(render_process_id),
85        render_view_id(render_view_id),
86        security_origin(request_security_origin),
87        requested_device_id(requested_device_id),
88        state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) {
89  }
90
91  ~DeviceRequest() {}
92
93  // Update the request state and notify observers.
94  void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
95    state_[stream_type] = new_state;
96
97    if (options.video_type != MEDIA_TAB_VIDEO_CAPTURE &&
98        options.audio_type != MEDIA_TAB_AUDIO_CAPTURE) {
99      return;
100    }
101
102    MediaObserver* media_observer =
103        GetContentClient()->browser()->GetMediaObserver();
104    if (media_observer == NULL)
105      return;
106
107    // If we appended a device_id scheme, we want to remove it when notifying
108    // observers which may be in different modules since this scheme is only
109    // used internally within the content module.
110    std::string device_id =
111        WebContentsCaptureUtil::StripWebContentsDeviceScheme(
112            requested_device_id);
113
114    media_observer->OnMediaRequestStateChanged(
115        render_process_id, render_view_id,
116        MediaStreamDevice(
117            stream_type, device_id, device_id), new_state);
118  }
119
120  MediaRequestState state(MediaStreamType stream_type) const {
121    return state_[stream_type];
122  }
123
124  MediaStreamRequester* const requester;  // Can be NULL.
125  const StreamOptions options;
126  const MediaStreamRequestType type;
127  const int render_process_id;
128  const int render_view_id;
129  const GURL security_origin;
130  const std::string requested_device_id;
131  StreamDeviceInfoArray devices;
132
133  // Callback to the requester which audio/video devices have been selected.
134  // It can be null if the requester has no interest to know the result.
135  // Currently it is only used by |DEVICE_ACCESS| type.
136  MediaRequestResponseCallback callback;
137
138 private:
139  std::vector<MediaRequestState> state_;
140};
141
142MediaStreamManager::EnumerationCache::EnumerationCache()
143    : valid(false) {
144}
145
146MediaStreamManager::EnumerationCache::~EnumerationCache() {
147}
148
149MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
150    : ui_controller_(new MediaStreamUIController(this)),
151      audio_manager_(audio_manager),
152      monitoring_started_(false),
153      io_loop_(NULL),
154      screen_capture_active_(false) {
155  DCHECK(audio_manager_);
156  memset(active_enumeration_ref_count_, 0,
157         sizeof(active_enumeration_ref_count_));
158
159  // Some unit tests create the MSM in the IO thread and assumes the
160  // initialization is done synchronously.
161  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
162    InitializeDeviceManagersOnIOThread();
163  } else {
164    BrowserThread::PostTask(
165        BrowserThread::IO, FROM_HERE,
166        base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread,
167                   base::Unretained(this)));
168  }
169}
170
171MediaStreamManager::~MediaStreamManager() {
172  DCHECK(requests_.empty());
173  DCHECK(!device_thread_.get());
174  DCHECK(!io_loop_);
175}
176
177VideoCaptureManager* MediaStreamManager::video_capture_manager() {
178  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
179  DCHECK(video_capture_manager_);
180  return video_capture_manager_;
181}
182
183AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
184  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185  DCHECK(audio_input_device_manager_);
186  return audio_input_device_manager_;
187}
188
189std::string MediaStreamManager::MakeMediaAccessRequest(
190    int render_process_id,
191    int render_view_id,
192    const StreamOptions& options,
193    const GURL& security_origin,
194    const MediaRequestResponseCallback& callback) {
195  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196  // Create a new request based on options.
197  DeviceRequest* request = new DeviceRequest(NULL,
198                                             options,
199                                             MEDIA_DEVICE_ACCESS,
200                                             render_process_id,
201                                             render_view_id,
202                                             security_origin,
203                                             std::string());
204  const std::string& label = AddRequest(request);
205
206  request->callback = callback;
207
208  HandleRequest(label);
209
210  return label;
211}
212
213std::string MediaStreamManager::GenerateStream(
214    MediaStreamRequester* requester,
215    int render_process_id,
216    int render_view_id,
217    const StreamOptions& options,
218    const GURL& security_origin) {
219  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220  if (CommandLine::ForCurrentProcess()->HasSwitch(
221          switches::kUseFakeDeviceForMediaStream)) {
222    UseFakeDevice();
223  }
224
225  int target_render_process_id = render_process_id;
226  int target_render_view_id = render_view_id;
227  std::string requested_device_id;
228
229  // Customize options for a WebContents based capture.
230  if (options.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
231      options.video_type == MEDIA_TAB_VIDEO_CAPTURE) {
232    // TODO(justinlin): Can't plumb audio mirroring using stream type right
233    // now, so plumbing by device_id. Will revisit once it's refactored.
234    // http://crbug.com/163100
235    requested_device_id =
236        WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
237            !options.video_device_id.empty() ?
238            options.video_device_id : options.audio_device_id);
239
240    bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
241        requested_device_id, &target_render_process_id, &target_render_view_id);
242    if (!has_valid_device_id ||
243        (options.audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
244         options.audio_type != MEDIA_NO_SERVICE) ||
245        (options.video_type != MEDIA_TAB_VIDEO_CAPTURE &&
246         options.video_type != MEDIA_NO_SERVICE)) {
247      LOG(ERROR) << "Invalid request.";
248      return std::string();
249    }
250  }
251
252  if (options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) {
253    if (options.audio_type != MEDIA_NO_SERVICE) {
254      // TODO(sergeyu): Surface error message to the calling JS code.
255      LOG(ERROR) << "Audio is not supported for screen capture streams.";
256      return std::string();
257    }
258
259    if (screen_capture_active_) {
260      // TODO(sergeyu): Implement support for more than one concurrent screen
261      // capture streams.
262      LOG(ERROR) << "Another screen capture stream is active.";
263      return std::string();
264    }
265
266    screen_capture_active_ = true;
267  }
268
269  // Create a new request based on options.
270  DeviceRequest* request = new DeviceRequest(requester,
271                                             options,
272                                             MEDIA_GENERATE_STREAM,
273                                             target_render_process_id,
274                                             target_render_view_id,
275                                             security_origin,
276                                             requested_device_id);
277  const std::string& label = AddRequest(request);
278  HandleRequest(label);
279  return label;
280}
281
282void MediaStreamManager::CancelRequest(const std::string& label) {
283  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
284
285  DeviceRequests::iterator it = requests_.find(label);
286  if (it != requests_.end()) {
287    // The request isn't complete, notify the UI immediately.
288    ui_controller_->CancelUIRequest(label);
289
290    if (!RequestDone(*it->second)) {
291      // TODO(xians): update the |state| to STATE_DONE to trigger a state
292      // changed notification to UI before deleting the request?
293      scoped_ptr<DeviceRequest> request(it->second);
294      RemoveRequest(it);
295      for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
296        const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
297        MediaStreamProvider* device_manager = GetDeviceManager(stream_type);
298        if (!device_manager)
299          continue;
300        if (request->state(stream_type) != MEDIA_REQUEST_STATE_OPENING) {
301          continue;
302        }
303        for (StreamDeviceInfoArray::const_iterator device_it =
304                 request->devices.begin();
305             device_it != request->devices.end(); ++device_it) {
306          if (device_it->device.type == stream_type) {
307            device_manager->Close(device_it->session_id);
308          }
309        }
310      }
311    } else {
312      StopGeneratedStream(label);
313    }
314  }
315}
316
317void MediaStreamManager::StopGeneratedStream(const std::string& label) {
318  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
319
320  // Find the request and close all open devices for the request.
321  DeviceRequests::iterator it = requests_.find(label);
322  if (it != requests_.end()) {
323    if (it->second->type == MEDIA_ENUMERATE_DEVICES) {
324      StopEnumerateDevices(label);
325      return;
326    }
327
328    scoped_ptr<DeviceRequest> request(it->second);
329    RemoveRequest(it);
330    for (StreamDeviceInfoArray::const_iterator device_it =
331             request->devices.begin();
332         device_it != request->devices.end(); ++device_it) {
333      GetDeviceManager(device_it->device.type)->Close(device_it->session_id);
334    }
335    if (request->type == MEDIA_GENERATE_STREAM &&
336        RequestDone(*request)) {
337      // Notify observers that this device is being closed.
338      for (int i = MEDIA_NO_SERVICE + 1; i != NUM_MEDIA_TYPES; ++i) {
339        if (request->state(static_cast<MediaStreamType>(i)) !=
340            MEDIA_REQUEST_STATE_NOT_REQUESTED) {
341          request->SetState(static_cast<MediaStreamType>(i),
342                            MEDIA_REQUEST_STATE_CLOSING);
343        }
344      }
345      NotifyUIDevicesClosed(label);
346    }
347
348    // If request isn't complete, notify the UI on the cancellation. And it
349    // is also safe to call CancelUIRequest if the request has been done.
350    ui_controller_->CancelUIRequest(label);
351  }
352}
353
354std::string MediaStreamManager::EnumerateDevices(
355    MediaStreamRequester* requester,
356    int render_process_id,
357    int render_view_id,
358    MediaStreamType type,
359    const GURL& security_origin) {
360  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
361  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
362         type == MEDIA_DEVICE_VIDEO_CAPTURE);
363
364  // When the requester is NULL, the request is made by the UI to ensure MSM
365  // starts monitoring devices.
366  if (!requester) {
367    if (!monitoring_started_)
368      StartMonitoring();
369
370    return std::string();
371  }
372
373  // Create a new request.
374  StreamOptions options;
375  EnumerationCache* cache = NULL;
376  if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
377    options.audio_type = type;
378    cache = &audio_enumeration_cache_;
379  } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) {
380    options.video_type = type;
381    cache = &video_enumeration_cache_;
382  } else {
383    NOTREACHED();
384    return std::string();
385  }
386
387  DeviceRequest* request = new DeviceRequest(requester,
388                                             options,
389                                             MEDIA_ENUMERATE_DEVICES,
390                                             render_process_id,
391                                             render_view_id,
392                                             security_origin,
393                                             std::string());
394  const std::string& label = AddRequest(request);
395
396  if (cache->valid) {
397    // Cached device list of this type exists. Just send it out.
398    request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED);
399
400    // Need to post a task since the requester won't have label till
401    // this function returns.
402    BrowserThread::PostTask(
403        BrowserThread::IO, FROM_HERE,
404        base::Bind(&MediaStreamManager::SendCachedDeviceList,
405                   base::Unretained(this), cache, label));
406  } else {
407    StartEnumeration(request);
408  }
409
410  return label;
411}
412
413void MediaStreamManager::StopEnumerateDevices(const std::string& label) {
414  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
415
416  DeviceRequests::iterator it = requests_.find(label);
417  if (it != requests_.end()) {
418    DCHECK_EQ(it->second->type, MEDIA_ENUMERATE_DEVICES);
419    // Delete the DeviceRequest.
420    scoped_ptr<DeviceRequest> request(it->second);
421    RemoveRequest(it);
422  }
423}
424
425std::string MediaStreamManager::OpenDevice(
426    MediaStreamRequester* requester,
427    int render_process_id,
428    int render_view_id,
429    const std::string& device_id,
430    MediaStreamType type,
431    const GURL& security_origin) {
432  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
433  DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
434         type == MEDIA_DEVICE_VIDEO_CAPTURE);
435
436  // Create a new request.
437  StreamOptions options;
438  if (IsAudioMediaType(type)) {
439    options.audio_type = type;
440  } else if (IsVideoMediaType(type)) {
441    options.video_type = type;
442  } else {
443    NOTREACHED();
444    return std::string();
445  }
446
447  DeviceRequest* request = new DeviceRequest(requester,
448                                             options,
449                                             MEDIA_OPEN_DEVICE,
450                                             render_process_id,
451                                             render_view_id,
452                                             security_origin,
453                                             device_id);
454  const std::string& label = AddRequest(request);
455  StartEnumeration(request);
456
457  return label;
458}
459
460void MediaStreamManager::NotifyUIDevicesOpened(const std::string& label) {
461  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
462  ui_controller_->NotifyUIIndicatorDevicesOpened(label);
463}
464
465void MediaStreamManager::NotifyUIDevicesClosed(const std::string& label) {
466  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
467  ui_controller_->NotifyUIIndicatorDevicesClosed(label);
468}
469
470void MediaStreamManager::SendCachedDeviceList(
471    EnumerationCache* cache,
472    const std::string& label) {
473  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
474  if (cache->valid) {
475    DeviceRequests::iterator it = requests_.find(label);
476    if (it != requests_.end()) {
477      it->second->requester->DevicesEnumerated(label, cache->devices);
478    }
479  }
480}
481
482void MediaStreamManager::StartMonitoring() {
483  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
484  if (!base::SystemMonitor::Get())
485    return;
486
487  if (!monitoring_started_) {
488    monitoring_started_ = true;
489    base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
490
491    // Enumerate both the audio and video devices to cache the device lists
492    // and send them to media observer.
493    ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE];
494    audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
495    ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE];
496    video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
497  }
498}
499
500void MediaStreamManager::StopMonitoring() {
501  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
502  if (monitoring_started_) {
503    base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
504    monitoring_started_ = false;
505    ClearEnumerationCache(&audio_enumeration_cache_);
506    ClearEnumerationCache(&video_enumeration_cache_);
507  }
508}
509
510void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
511  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
512  cache->valid = false;
513}
514
515void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
516  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
517
518  // Start monitoring the devices when doing the first enumeration.
519  if (!monitoring_started_ && base::SystemMonitor::Get()) {
520    StartMonitoring();
521  }
522
523  // Start enumeration for devices of all requested device types.
524  for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
525    const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
526    if (Requested(request->options, stream_type)) {
527      request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED);
528      DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
529      if (active_enumeration_ref_count_[stream_type] == 0) {
530        ++active_enumeration_ref_count_[stream_type];
531        GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
532      }
533    }
534  }
535}
536
537std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
538  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
539
540  // Create a label for this request and verify it is unique.
541  std::string unique_label;
542  do {
543    unique_label = RandomLabel();
544  } while (requests_.find(unique_label) != requests_.end());
545
546  requests_.insert(std::make_pair(unique_label, request));
547
548  return unique_label;
549}
550
551void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) {
552  if (it->second->options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) {
553    DCHECK(screen_capture_active_);
554    screen_capture_active_ = false;
555  }
556
557  NotifyUIDevicesClosed(it->first);
558
559  requests_.erase(it);
560}
561
562void MediaStreamManager::PostRequestToUI(const std::string& label) {
563  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
564  DeviceRequest* request = requests_[label];
565  // Get user confirmation to use capture devices.
566  ui_controller_->MakeUIRequest(label,
567                                request->render_process_id,
568                                request->render_view_id,
569                                request->options,
570                                request->security_origin,
571                                request->type,
572                                request->requested_device_id);
573}
574
575void MediaStreamManager::HandleRequest(const std::string& label) {
576  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
577  DeviceRequest* request = requests_[label];
578
579  const MediaStreamType audio_type = request->options.audio_type;
580  const MediaStreamType video_type = request->options.video_type;
581
582  bool is_web_contents_capture =
583      audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
584      video_type == MEDIA_TAB_VIDEO_CAPTURE;
585
586  bool is_screen_capure =
587      video_type == MEDIA_SCREEN_VIDEO_CAPTURE;
588
589  if (!is_web_contents_capture &&
590      !is_screen_capure &&
591      ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) ||
592       (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) {
593    // Enumerate the devices if there is no valid device lists to be used.
594    StartEnumeration(request);
595    return;
596  }
597
598  // No need to do new device enumerations, post the request to UI
599  // immediately.
600  if (IsAudioMediaType(audio_type))
601    request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
602  if (IsVideoMediaType(video_type))
603    request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
604
605  PostRequestToUI(label);
606}
607
608void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
609  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
610  if (device_thread_)
611    return;
612
613  device_thread_.reset(new base::Thread("MediaStreamDeviceThread"));
614#if defined(OS_WIN)
615  device_thread_->init_com_with_mta(true);
616#endif
617  CHECK(device_thread_->Start());
618
619  audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_);
620  audio_input_device_manager_->Register(this,
621                                        device_thread_->message_loop_proxy());
622
623  video_capture_manager_ = new VideoCaptureManager();
624  video_capture_manager_->Register(this, device_thread_->message_loop_proxy());
625
626  // We want to be notified of IO message loop destruction to delete the thread
627  // and the device managers.
628  io_loop_ = base::MessageLoop::current();
629  io_loop_->AddDestructionObserver(this);
630}
631
632void MediaStreamManager::Opened(MediaStreamType stream_type,
633                                int capture_session_id) {
634  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
635
636  // Find the request containing this device and mark it as used.
637  DeviceRequest* request = NULL;
638  StreamDeviceInfoArray* devices = NULL;
639  std::string label;
640  for (DeviceRequests::iterator request_it = requests_.begin();
641       request_it != requests_.end() && request == NULL; ++request_it) {
642    devices = &(request_it->second->devices);
643    for (StreamDeviceInfoArray::iterator device_it = devices->begin();
644         device_it != devices->end(); ++device_it) {
645      if (device_it->device.type == stream_type &&
646          device_it->session_id == capture_session_id) {
647        // We've found the request.
648        device_it->in_use = true;
649        label = request_it->first;
650        request = request_it->second;
651        break;
652      }
653    }
654  }
655  if (request == NULL) {
656    // The request doesn't exist.
657    return;
658  }
659
660  DCHECK_NE(request->state(stream_type), MEDIA_REQUEST_STATE_REQUESTED);
661
662  // Check if all devices for this stream type are opened. Update the state if
663  // they are.
664  for (StreamDeviceInfoArray::iterator device_it = devices->begin();
665       device_it != devices->end(); ++device_it) {
666    if (device_it->device.type != stream_type) {
667      continue;
668    }
669    if (device_it->in_use == false) {
670      // Wait for more devices to be opened before we're done.
671      return;
672    }
673  }
674
675  request->SetState(stream_type, MEDIA_REQUEST_STATE_DONE);
676
677  if (!RequestDone(*request)) {
678    // This stream_type is done, but not the other type.
679    return;
680  }
681
682  switch (request->type) {
683    case MEDIA_OPEN_DEVICE:
684      request->requester->DeviceOpened(label, devices->front());
685      break;
686    case MEDIA_GENERATE_STREAM: {
687      // Partition the array of devices into audio vs video.
688      StreamDeviceInfoArray audio_devices, video_devices;
689      for (StreamDeviceInfoArray::iterator device_it = devices->begin();
690           device_it != devices->end(); ++device_it) {
691        if (IsAudioMediaType(device_it->device.type)) {
692          // Store the native audio parameters in the device struct.
693          // TODO(xians): Handle the tab capture sample rate/channel layout
694          // in AudioInputDeviceManager::Open().
695          if (device_it->device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
696            const StreamDeviceInfo* info =
697                audio_input_device_manager_->GetOpenedDeviceInfoById(
698                    device_it->session_id);
699            DCHECK_EQ(info->device.id, device_it->device.id);
700            device_it->device.sample_rate = info->device.sample_rate;
701            device_it->device.channel_layout = info->device.channel_layout;
702          }
703          audio_devices.push_back(*device_it);
704        } else if (IsVideoMediaType(device_it->device.type)) {
705          video_devices.push_back(*device_it);
706        } else {
707          NOTREACHED();
708        }
709      }
710
711      request->requester->StreamGenerated(label, audio_devices, video_devices);
712      NotifyUIDevicesOpened(label);
713      break;
714    }
715    default:
716      NOTREACHED();
717      break;
718  }
719}
720
721void MediaStreamManager::Closed(MediaStreamType stream_type,
722                                int capture_session_id) {
723  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
724}
725
726void MediaStreamManager::DevicesEnumerated(
727    MediaStreamType stream_type, const StreamDeviceInfoArray& devices) {
728  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
729
730  // Only cache the device list when the device list has been changed.
731  bool need_update_clients = false;
732  EnumerationCache* cache =
733      stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
734      &audio_enumeration_cache_ : &video_enumeration_cache_;
735  if (!cache->valid ||
736      devices.size() != cache->devices.size() ||
737      !std::equal(devices.begin(), devices.end(), cache->devices.begin(),
738                  StreamDeviceInfo::IsEqual)) {
739    cache->valid = true;
740    cache->devices = devices;
741    need_update_clients = true;
742  }
743
744  if (need_update_clients && monitoring_started_)
745    NotifyDevicesChanged(stream_type, devices);
746
747  // Publish the result for all requests waiting for device list(s).
748  // Find the requests waiting for this device list, store their labels and
749  // release the iterator before calling device settings. We might get a call
750  // back from device_settings that will need to iterate through devices.
751  std::list<std::string> label_list;
752  for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
753       ++it) {
754    if (it->second->state(stream_type) ==
755        MEDIA_REQUEST_STATE_REQUESTED &&
756        Requested(it->second->options, stream_type)) {
757      if (it->second->type != MEDIA_ENUMERATE_DEVICES)
758        it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
759      label_list.push_back(it->first);
760    }
761  }
762  for (std::list<std::string>::iterator it = label_list.begin();
763       it != label_list.end(); ++it) {
764    DeviceRequest* request = requests_[*it];
765    switch (request->type) {
766      case MEDIA_ENUMERATE_DEVICES:
767        if (need_update_clients && request->requester)
768          request->requester->DevicesEnumerated(*it, devices);
769        break;
770      default:
771        if (request->state(request->options.audio_type) ==
772                MEDIA_REQUEST_STATE_REQUESTED ||
773            request->state(request->options.video_type) ==
774                MEDIA_REQUEST_STATE_REQUESTED) {
775          // We are doing enumeration for other type of media, wait until it is
776          // all done before posting the request to UI because UI needs
777          // the device lists to handle the request.
778          break;
779        }
780
781        // Post the request to UI for permission approval.
782        PostRequestToUI(*it);
783        break;
784    }
785  }
786  label_list.clear();
787  --active_enumeration_ref_count_[stream_type];
788  DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
789}
790
791void MediaStreamManager::Error(MediaStreamType stream_type,
792                               int capture_session_id,
793                               MediaStreamProviderError error) {
794  // Find the device for the error call.
795  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
796
797  for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
798       ++it) {
799    StreamDeviceInfoArray& devices = it->second->devices;
800
801    // TODO(miu): BUG.  It's possible for the audio (or video) device array in
802    // the "requester" to become out-of-sync with the order of devices we have
803    // here.  See http://crbug.com/147650
804    int audio_device_idx = -1;
805    int video_device_idx = -1;
806    for (StreamDeviceInfoArray::iterator device_it = devices.begin();
807         device_it != devices.end(); ++device_it) {
808      if (IsAudioMediaType(device_it->device.type)) {
809        ++audio_device_idx;
810      } else if (IsVideoMediaType(device_it->device.type)) {
811        ++video_device_idx;
812      } else {
813        NOTREACHED();
814        continue;
815      }
816      if (device_it->device.type != stream_type ||
817          device_it->session_id != capture_session_id) {
818        continue;
819      }
820      // We've found the failing device. Find the error case:
821      // An error should only be reported to the MediaStreamManager if
822      // the request has not been fulfilled yet.
823      DCHECK(it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE);
824      if (it->second->state(stream_type) != MEDIA_REQUEST_STATE_DONE) {
825        // Request is not done, devices are not opened in this case.
826        if (devices.size() <= 1) {
827          scoped_ptr<DeviceRequest> request(it->second);
828          // 1. Device not opened and no other devices for this request ->
829          //    signal stream error and remove the request.
830          if (request->requester)
831            request->requester->StreamGenerationFailed(it->first);
832
833          RemoveRequest(it);
834        } else {
835          // 2. Not opened but other devices exists for this request -> remove
836          //    device from list, but don't signal an error.
837          devices.erase(device_it);  // NOTE: This invalidates device_it!
838        }
839      }
840      return;
841    }
842  }
843}
844
845void MediaStreamManager::DevicesAccepted(const std::string& label,
846                                         const StreamDeviceInfoArray& devices) {
847  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
848  DCHECK(!devices.empty());
849  DeviceRequests::iterator request_it = requests_.find(label);
850  if (request_it == requests_.end()) {
851    return;
852  }
853
854  if (request_it->second->type == MEDIA_DEVICE_ACCESS) {
855    scoped_ptr<DeviceRequest> request(request_it->second);
856    if (!request->callback.is_null()) {
857      // Map the devices to MediaStreamDevices.
858      MediaStreamDevices selected_devices;
859      for (StreamDeviceInfoArray::const_iterator it = devices.begin();
860           it != devices.end(); ++it) {
861        selected_devices.push_back(it->device);
862      }
863
864      request->callback.Run(label, selected_devices);
865    }
866
867    // Delete the request since it is done.
868    RemoveRequest(request_it);
869    return;
870  }
871
872  // Process all newly-accepted devices for this request.
873  DeviceRequest* request = request_it->second;
874  bool found_audio = false, found_video = false;
875  for (StreamDeviceInfoArray::const_iterator device_it = devices.begin();
876       device_it != devices.end(); ++device_it) {
877    StreamDeviceInfo device_info = *device_it;  // Make a copy.
878
879    // TODO(justinlin): Nicer way to do this?
880    // Re-append the device's id since we lost it when posting request to UI.
881    if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
882        device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
883      device_info.device.id = request->requested_device_id;
884
885      // Initialize the sample_rate and channel_layout here since for audio
886      // mirroring, we don't go through EnumerateDevices where these are usually
887      // initialized.
888      if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
889        const media::AudioParameters parameters =
890            audio_manager_->GetDefaultOutputStreamParameters();
891        int sample_rate = parameters.sample_rate();
892        // If we weren't able to get the native sampling rate or the sample_rate
893        // is outside the valid range for input devices set reasonable defaults.
894        if (sample_rate <= 0 || sample_rate > 96000)
895          sample_rate = 44100;
896
897        device_info.device.sample_rate = sample_rate;
898        device_info.device.channel_layout = media::CHANNEL_LAYOUT_STEREO;
899      }
900    }
901
902    // Set in_use to false to be able to track if this device has been
903    // opened. in_use might be true if the device type can be used in more
904    // than one session.
905    DCHECK_EQ(request->state(device_it->device.type),
906              MEDIA_REQUEST_STATE_PENDING_APPROVAL);
907    device_info.in_use = false;
908
909    device_info.session_id =
910        GetDeviceManager(device_info.device.type)->Open(device_info);
911    request->SetState(device_it->device.type, MEDIA_REQUEST_STATE_OPENING);
912    request->devices.push_back(device_info);
913
914    if (device_info.device.type == request->options.audio_type) {
915      found_audio = true;
916    } else if (device_info.device.type == request->options.video_type) {
917      found_video = true;
918    }
919  }
920
921  // Check whether we've received all stream types requested.
922  if (!found_audio && IsAudioMediaType(request->options.audio_type))
923    request->SetState(request->options.audio_type, MEDIA_REQUEST_STATE_ERROR);
924
925  if (!found_video && IsVideoMediaType(request->options.video_type))
926    request->SetState(request->options.video_type, MEDIA_REQUEST_STATE_ERROR);
927}
928
929void MediaStreamManager::SettingsError(const std::string& label) {
930  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
931  // Erase this request and report an error.
932  DeviceRequests::iterator it = requests_.find(label);
933  if (it == requests_.end())
934    return;
935
936  // Notify the users about the request result.
937  scoped_ptr<DeviceRequest> request(it->second);
938  if (request->requester)
939    request->requester->StreamGenerationFailed(label);
940
941  if (request->type == MEDIA_DEVICE_ACCESS &&
942      !request->callback.is_null()) {
943    request->callback.Run(label, MediaStreamDevices());
944  }
945
946  RemoveRequest(it);
947}
948
949void MediaStreamManager::StopStreamFromUI(const std::string& label) {
950  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
951
952  DeviceRequests::iterator it = requests_.find(label);
953  if (it == requests_.end())
954    return;
955
956  // Notify renderers that the stream has been stopped.
957  if (it->second->requester)
958    it->second->requester->StreamGenerationFailed(label);
959
960  StopGeneratedStream(label);
961}
962
963void MediaStreamManager::GetAvailableDevices(MediaStreamDevices* devices) {
964  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
965  DCHECK(audio_enumeration_cache_.valid || video_enumeration_cache_.valid);
966  DCHECK(devices->empty());
967  if (audio_enumeration_cache_.valid) {
968    for (StreamDeviceInfoArray::const_iterator it =
969             audio_enumeration_cache_.devices.begin();
970         it != audio_enumeration_cache_.devices.end();
971         ++it) {
972      devices->push_back(it->device);
973    }
974  }
975
976  if (video_enumeration_cache_.valid) {
977    for (StreamDeviceInfoArray::const_iterator it =
978             video_enumeration_cache_.devices.begin();
979         it != video_enumeration_cache_.devices.end();
980         ++it) {
981      devices->push_back(it->device);
982    }
983  }
984}
985
986void MediaStreamManager::UseFakeDevice() {
987  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
988  video_capture_manager()->UseFakeDevice();
989  audio_input_device_manager()->UseFakeDevice();
990  UseFakeUI(scoped_ptr<MediaStreamUI>());
991}
992
993void MediaStreamManager::UseFakeUI(scoped_ptr<MediaStreamUI> fake_ui) {
994  ui_controller_->UseFakeUI(fake_ui.Pass());
995}
996
997void MediaStreamManager::WillDestroyCurrentMessageLoop() {
998  DCHECK_EQ(base::MessageLoop::current(), io_loop_);
999  DCHECK(requests_.empty());
1000  if (device_thread_) {
1001    StopMonitoring();
1002
1003    video_capture_manager_->Unregister();
1004    audio_input_device_manager_->Unregister();
1005    device_thread_.reset();
1006  }
1007
1008  audio_input_device_manager_ = NULL;
1009  video_capture_manager_ = NULL;
1010  io_loop_ = NULL;
1011  ui_controller_.reset();
1012}
1013
1014void MediaStreamManager::NotifyDevicesChanged(
1015    MediaStreamType stream_type,
1016    const StreamDeviceInfoArray& devices) {
1017  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1018  MediaObserver* media_observer =
1019      GetContentClient()->browser()->GetMediaObserver();
1020  if (media_observer == NULL)
1021    return;
1022
1023  // Map the devices to MediaStreamDevices.
1024  MediaStreamDevices new_devices;
1025  for (StreamDeviceInfoArray::const_iterator it = devices.begin();
1026       it != devices.end(); ++it) {
1027    new_devices.push_back(it->device);
1028  }
1029
1030  if (IsAudioMediaType(stream_type)) {
1031    media_observer->OnAudioCaptureDevicesChanged(new_devices);
1032  } else if (IsVideoMediaType(stream_type)) {
1033    media_observer->OnVideoCaptureDevicesChanged(new_devices);
1034  } else {
1035    NOTREACHED();
1036  }
1037}
1038
1039bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
1040  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1041
1042  const bool requested_audio = IsAudioMediaType(request.options.audio_type);
1043  const bool requested_video = IsVideoMediaType(request.options.video_type);
1044
1045  const bool audio_done =
1046      !requested_audio ||
1047      request.state(request.options.audio_type) ==
1048      MEDIA_REQUEST_STATE_DONE ||
1049      request.state(request.options.audio_type) ==
1050      MEDIA_REQUEST_STATE_ERROR;
1051  if (!audio_done)
1052    return false;
1053
1054  const bool video_done =
1055      !requested_video ||
1056      request.state(request.options.video_type) ==
1057      MEDIA_REQUEST_STATE_DONE ||
1058      request.state(request.options.video_type) ==
1059      MEDIA_REQUEST_STATE_ERROR;
1060  if (!video_done)
1061    return false;
1062
1063  for (StreamDeviceInfoArray::const_iterator it = request.devices.begin();
1064       it != request.devices.end(); ++it) {
1065    if (it->in_use == false)
1066      return false;
1067  }
1068
1069  return true;
1070}
1071
1072MediaStreamProvider* MediaStreamManager::GetDeviceManager(
1073    MediaStreamType stream_type) {
1074  if (IsVideoMediaType(stream_type)) {
1075    return video_capture_manager();
1076  } else if (IsAudioMediaType(stream_type)) {
1077    return audio_input_device_manager();
1078  }
1079  NOTREACHED();
1080  return NULL;
1081}
1082
1083void MediaStreamManager::OnDevicesChanged(
1084    base::SystemMonitor::DeviceType device_type) {
1085  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1086
1087  // NOTE: This method is only called in response to physical audio/video device
1088  // changes (from the operating system).
1089
1090  MediaStreamType stream_type;
1091  if (device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE) {
1092    stream_type = MEDIA_DEVICE_AUDIO_CAPTURE;
1093  } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) {
1094    stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
1095  } else {
1096    return;  // Uninteresting device change.
1097  }
1098
1099  // Always do enumeration even though some enumeration is in progress,
1100  // because those enumeration commands could be sent before these devices
1101  // change.
1102  ++active_enumeration_ref_count_[stream_type];
1103  GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
1104}
1105
1106}  // namespace content
1107