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// MediaStreamManager is used to open/enumerate media capture devices (video
6// supported now). Call flow:
7// 1. GenerateStream is called when a render process wants to use a capture
8//    device.
9// 2. MediaStreamManager will ask MediaStreamUIController for permission to
10//    use devices and for which device to use.
11// 3. MediaStreamManager will request the corresponding media device manager(s)
12//    to enumerate available devices. The result will be given to
13//    MediaStreamUIController.
14// 4. MediaStreamUIController will, by posting the request to UI, let the
15//    users to select which devices to use and send callback to
16//    MediaStreamManager with the result.
17// 5. MediaStreamManager will call the proper media device manager to open the
18//    device and let the MediaStreamRequester know it has been done.
19
20// When enumeration and open are done in separate operations,
21// MediaStreamUIController is not involved as in steps.
22
23#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
24#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
25
26#include <map>
27#include <string>
28
29#include "base/basictypes.h"
30#include "base/memory/ref_counted.h"
31#include "base/memory/scoped_ptr.h"
32#include "base/message_loop/message_loop.h"
33#include "base/system_monitor/system_monitor.h"
34#include "content/browser/renderer_host/media/media_stream_provider.h"
35#include "content/common/content_export.h"
36#include "content/common/media/media_stream_options.h"
37#include "content/public/browser/media_request_state.h"
38#include "content/public/browser/resource_context.h"
39
40namespace base {
41class Thread;
42}
43
44namespace media {
45class AudioManager;
46}
47
48namespace content {
49
50class AudioInputDeviceManager;
51class FakeMediaStreamUIProxy;
52class MediaStreamDeviceSettings;
53class MediaStreamRequester;
54class MediaStreamUIProxy;
55class VideoCaptureManager;
56
57// MediaStreamManager is used to generate and close new media devices, not to
58// start the media flow. The classes requesting new media streams are answered
59// using MediaStreamRequester.
60class CONTENT_EXPORT MediaStreamManager
61    : public MediaStreamProviderListener,
62      public base::MessageLoop::DestructionObserver,
63      public base::SystemMonitor::DevicesChangedObserver {
64 public:
65  // Callback to deliver the result of a media request.
66  typedef base::Callback<void(const MediaStreamDevices& devices,
67                              scoped_ptr<MediaStreamUIProxy> ui)>
68      MediaRequestResponseCallback;
69
70  explicit MediaStreamManager(media::AudioManager* audio_manager);
71  virtual ~MediaStreamManager();
72
73  // Used to access VideoCaptureManager.
74  VideoCaptureManager* video_capture_manager();
75
76  // Used to access AudioInputDeviceManager.
77  AudioInputDeviceManager* audio_input_device_manager();
78
79  // Creates a new media access request which is identified by a unique string
80  // that's returned to the caller. This will trigger the infobar and ask users
81  // for access to the device. |render_process_id| and |render_view_id| refer
82  // to the view where the infobar will appear to the user. |callback| is
83  // used to send the selected device to the clients. An empty list of device
84  // will be returned if the users deny the access.
85  std::string MakeMediaAccessRequest(
86      int render_process_id,
87      int render_view_id,
88      int page_request_id,
89      const StreamOptions& options,
90      const GURL& security_origin,
91      const MediaRequestResponseCallback& callback);
92
93  // GenerateStream opens new media devices according to |components|.  It
94  // creates a new request which is identified by a unique string that's
95  // returned to the caller.  |render_process_id| and |render_view_id| refer to
96  // the view where the infobar will appear to the user.
97  void GenerateStream(MediaStreamRequester* requester,
98                      int render_process_id,
99                      int render_view_id,
100                      const ResourceContext::SaltCallback& sc,
101                      int page_request_id,
102                      const StreamOptions& components,
103                      const GURL& security_origin);
104
105  void CancelRequest(int render_process_id,
106                     int render_view_id,
107                     int page_request_id);
108
109  // Cancel an open request identified by |label|.
110  virtual void CancelRequest(const std::string& label);
111
112  // Cancel all requests for the given |render_process_id|.
113  void CancelAllRequests(int render_process_id);
114
115  // Closes the stream device for a certain render view. The stream must have
116  // been opened by a call to GenerateStream.
117  void StopStreamDevice(int render_process_id,
118                        int render_view_id,
119                        const std::string& device_id);
120
121  // Gets a list of devices of |type|, which must be MEDIA_DEVICE_AUDIO_CAPTURE
122  // or MEDIA_DEVICE_VIDEO_CAPTURE.
123  // The request is identified using the string returned to the caller.
124  // When the |requester| is NULL, MediaStreamManager will enumerate both audio
125  // and video devices and also start monitoring device changes, such as
126  // plug/unplug. The new device lists will be delivered via media observer to
127  // MediaCaptureDevicesDispatcher.
128  virtual std::string EnumerateDevices(MediaStreamRequester* requester,
129                                       int render_process_id,
130                                       int render_view_id,
131                                       const ResourceContext::SaltCallback& sc,
132                                       int page_request_id,
133                                       MediaStreamType type,
134                                       const GURL& security_origin);
135
136  // Open a device identified by |device_id|.  |type| must be either
137  // MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
138  // The request is identified using string returned to the caller.
139  void OpenDevice(MediaStreamRequester* requester,
140                  int render_process_id,
141                  int render_view_id,
142                  const ResourceContext::SaltCallback& sc,
143                  int page_request_id,
144                  const std::string& device_id,
145                  MediaStreamType type,
146                  const GURL& security_origin);
147
148  // Called by UI to make sure the device monitor is started so that UI receive
149  // notifications about device changes.
150  void EnsureDeviceMonitorStarted();
151
152  // Implements MediaStreamProviderListener.
153  virtual void Opened(MediaStreamType stream_type,
154                      int capture_session_id) OVERRIDE;
155  virtual void Closed(MediaStreamType stream_type,
156                      int capture_session_id) OVERRIDE;
157  virtual void DevicesEnumerated(MediaStreamType stream_type,
158                                 const StreamDeviceInfoArray& devices) OVERRIDE;
159
160  // Implements base::SystemMonitor::DevicesChangedObserver.
161  virtual void OnDevicesChanged(
162      base::SystemMonitor::DeviceType device_type) OVERRIDE;
163
164  // Used by unit test to make sure fake devices are used instead of a real
165  // devices, which is needed for server based testing or certain tests (which
166  // can pass --use-fake-device-for-media-stream).
167  void UseFakeDevice();
168
169  // Called by the tests to specify a fake UI that should be used for next
170  // generated stream (or when using --use-fake-ui-for-media-stream).
171  void UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy> fake_ui);
172
173  // Returns all devices currently opened by a request with label |label|.
174  // If no request with |label| exist, an empty array is returned.
175  StreamDeviceInfoArray GetDevicesOpenedByRequest(
176      const std::string& label) const;
177
178  // This object gets deleted on the UI thread after the IO thread has been
179  // destroyed. So we need to know when IO thread is being destroyed so that
180  // we can delete VideoCaptureManager and AudioInputDeviceManager. Normally
181  // this is handled by
182  // base::MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop.
183  // But for some tests which use TestBrowserThreadBundle, we need to call
184  // WillDestroyCurrentMessageLoop explicitly because the notification happens
185  // too late. (see http://crbug.com/247525#c14).
186  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
187
188 protected:
189  // Used for testing.
190  MediaStreamManager();
191
192 private:
193  // Contains all data needed to keep track of requests.
194  class DeviceRequest;
195
196  // Cache enumerated device list.
197  struct EnumerationCache {
198    EnumerationCache();
199    ~EnumerationCache();
200
201    bool valid;
202    StreamDeviceInfoArray devices;
203  };
204
205  typedef std::map<std::string, DeviceRequest*> DeviceRequests;
206
207  // Initializes the device managers on IO thread.  Auto-starts the device
208  // thread and registers this as a listener with the device managers.
209  void InitializeDeviceManagersOnIOThread();
210
211  // Helper for sending up-to-date device lists to media observer when a
212  // capture device is plugged in or unplugged.
213  void NotifyDevicesChanged(MediaStreamType stream_type,
214                            const StreamDeviceInfoArray& devices);
215
216  void HandleAccessRequestResponse(const std::string& label,
217                                   const MediaStreamDevices& devices);
218  void StopMediaStreamFromBrowser(const std::string& label);
219
220  void DoEnumerateDevices(const std::string& label);
221
222  // Helpers.
223  // Checks if all devices that was requested in the request identififed by
224  // |label| has been opened and set the request state accordingly.
225  void HandleRequestDone(const std::string& label,
226                         DeviceRequest* request);
227  // Stop the use of the device associated with |session_id| of type |type| in
228  // all |requests_|. The device is removed from the request. If a request
229  /// doesn't use any devices as a consequence, the request is deleted.
230  void StopDevice(MediaStreamType type, int session_id);
231  // Calls the correct capture manager and close the device with |session_id|.
232  // All requests that uses the device are updated.
233  void CloseDevice(MediaStreamType type, int session_id);
234  // Returns true if a request for devices has been completed and the devices
235  // has either been opened or an error has occurred.
236  bool RequestDone(const DeviceRequest& request) const;
237  MediaStreamProvider* GetDeviceManager(MediaStreamType stream_type);
238  void StartEnumeration(DeviceRequest* request);
239  std::string AddRequest(DeviceRequest* request);
240  DeviceRequest* FindRequest(const std::string& label) const;
241  void DeleteRequest(const std::string& label);
242  void ClearEnumerationCache(EnumerationCache* cache);
243  // Prepare the request with label |label| by starting device enumeration if
244  // needed.
245  void SetupRequest(const std::string& label);
246  // Prepare |request| of type MEDIA_DEVICE_AUDIO_CAPTURE and/or
247  // MEDIA_DEVICE_VIDEO_CAPTURE for being posted to the UI by parsing
248  // StreamOptions::Constraints for requested device IDs.
249  bool SetupDeviceCaptureRequest(DeviceRequest* request);
250  // Prepare |request| of type MEDIA_TAB_AUDIO_CAPTURE and/or
251  // MEDIA_TAB_VIDEO_CAPTURE for being posted to the UI by parsing
252  // StreamOptions::Constraints for requested tab capture IDs.
253  bool SetupTabCaptureRequest(DeviceRequest* request);
254  // Prepare |request| of type MEDIA_LOOPBACK_AUDIO_CAPTURE and/or
255  // MEDIA_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
256  // StreamOptions::Constraints for the requested desktop ID.
257  bool SetupScreenCaptureRequest(DeviceRequest* request);
258  // Called when a request has been setup and devices have been enumerated if
259  // needed.
260  void PostRequestToUI(const std::string& label, DeviceRequest* request);
261  // Returns true if a device with |device_id| has already been requested with
262  // a render procecss_id and render_view_id and type equal to the the values
263  // in |request|. If it has been requested, |device_info| contain information
264  // about the device.
265  bool FindExistingRequestedDeviceInfo(
266      const DeviceRequest& new_request,
267      const MediaStreamDevice& new_device_info,
268      StreamDeviceInfo* existing_device_info,
269      MediaRequestState* existing_request_state) const;
270
271  void FinalizeGenerateStream(const std::string& label,
272                              DeviceRequest* request);
273  void FinalizeRequestFailed(const std::string& label,
274                             DeviceRequest* request);
275  void FinalizeOpenDevice(const std::string& label,
276                          DeviceRequest* request);
277  void FinalizeMediaAccessRequest(const std::string& label,
278                                  DeviceRequest* request,
279                                  const MediaStreamDevices& devices);
280  void FinalizeEnumerateDevices(const std::string& label,
281                                DeviceRequest* request);
282
283  // This method is called when an audio or video device is plugged in or
284  // removed. It make sure all MediaStreams that use a removed device is
285  // stopped and that the render process is notified. |old_devices| is the list
286  // of previously available devices. |new_devices| is the new
287  // list of currently available devices.
288  void StopRemovedDevices(const StreamDeviceInfoArray& old_devices,
289                          const StreamDeviceInfoArray& new_devices);
290  // Helper method used by StopRemovedDevices to stop the use of a certain
291  // device.
292  void StopRemovedDevice(const MediaStreamDevice& device);
293
294  // Helpers to start and stop monitoring devices.
295  void StartMonitoring();
296  void StopMonitoring();
297
298  // Finds the requested device id from constraints. The requested device type
299  // must be MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
300  bool GetRequestedDeviceCaptureId(const DeviceRequest* request,
301                                   MediaStreamType type,
302                                   std::string* device_id) const;
303
304  void TranslateDeviceIdToSourceId(DeviceRequest* request,
305                                   MediaStreamDevice* device);
306
307  // Finds and returns the device id corresponding to the given
308  // |source_id|. Returns true if there was a raw device id that matched the
309  // given |source_id|, false if nothing matched it.
310  bool TranslateSourceIdToDeviceId(
311      MediaStreamType stream_type,
312      const ResourceContext::SaltCallback& rc,
313      const GURL& security_origin,
314      const std::string& source_id,
315      std::string* device_id) const;
316
317  // Device thread shared by VideoCaptureManager and AudioInputDeviceManager.
318  scoped_ptr<base::Thread> device_thread_;
319
320  media::AudioManager* const audio_manager_;  // not owned
321  scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
322  scoped_refptr<VideoCaptureManager> video_capture_manager_;
323
324  // Indicator of device monitoring state.
325  bool monitoring_started_;
326
327  // Stores most recently enumerated device lists. The cache is cleared when
328  // monitoring is stopped or there is no request for that type of device.
329  EnumerationCache audio_enumeration_cache_;
330  EnumerationCache video_enumeration_cache_;
331
332  // Keeps track of live enumeration commands sent to VideoCaptureManager or
333  // AudioInputDeviceManager, in order to only enumerate when necessary.
334  int active_enumeration_ref_count_[NUM_MEDIA_TYPES];
335
336  // All non-closed request.
337  DeviceRequests requests_;
338
339  // Hold a pointer to the IO loop to check we delete the device thread and
340  // managers on the right thread.
341  base::MessageLoop* io_loop_;
342
343  bool use_fake_ui_;
344  scoped_ptr<FakeMediaStreamUIProxy> fake_ui_;
345
346  DISALLOW_COPY_AND_ASSIGN(MediaStreamManager);
347};
348
349}  // namespace content
350
351#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
352