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