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 #ifndef CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_CAPTURE_INDICATOR_H_
6 #define CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_CAPTURE_INDICATOR_H_
7 
8 #include <unordered_map>
9 #include <vector>
10 
11 #include "base/callback_forward.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/observer_list.h"
15 #include "chrome/browser/status_icons/status_icon_menu_model.h"
16 #include "content/public/browser/media_stream_request.h"
17 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
18 #include "ui/gfx/native_widget_types.h"
19 
20 namespace content {
21 class WebContents;
22 }  // namespace content
23 
24 namespace gfx {
25 class ImageSkia;
26 }  // namespace gfx
27 
28 class StatusIcon;
29 
30 // Interface to display custom UI during stream capture.
31 class MediaStreamUI {
32  public:
33   // Called when stream capture is stopped.
34   virtual ~MediaStreamUI() = default;
35 
36   // Called when stream capture starts.
37   // |stop_callback| is a callback to stop the stream.
38   // |source_callback| is a callback to change the desktop capture source.
39   // Returns the platform-dependent window ID for the UI, or 0 if not
40   // applicable.
41   virtual gfx::NativeViewId OnStarted(
42       base::OnceClosure stop_callback,
43       content::MediaStreamUI::SourceCallback source_callback) = 0;
44 
45   // Replaces the stop callback set in OnStarted(), if any.
46   virtual void SetStopCallback(base::OnceClosure stop) = 0;
47 };
48 
49 // Keeps track of which WebContents are capturing media streams. Used to display
50 // indicators (e.g. in the tab strip, via notifications) and to make resource
51 // allocation decisions (e.g. WebContents capturing streams are not discarded).
52 //
53 // Owned by MediaCaptureDevicesDispatcher, which is a singleton.
54 class MediaStreamCaptureIndicator
55     : public base::RefCountedThreadSafe<MediaStreamCaptureIndicator>,
56       public StatusIconMenuModel::Delegate {
57  public:
58   class Observer : public base::CheckedObserver {
59    public:
OnIsCapturingVideoChanged(content::WebContents * web_contents,bool is_capturing_video)60     virtual void OnIsCapturingVideoChanged(content::WebContents* web_contents,
61                                            bool is_capturing_video) {}
OnIsCapturingAudioChanged(content::WebContents * web_contents,bool is_capturing_audio)62     virtual void OnIsCapturingAudioChanged(content::WebContents* web_contents,
63                                            bool is_capturing_audio) {}
OnIsBeingMirroredChanged(content::WebContents * web_contents,bool is_being_mirrored)64     virtual void OnIsBeingMirroredChanged(content::WebContents* web_contents,
65                                           bool is_being_mirrored) {}
OnIsCapturingWindowChanged(content::WebContents * web_contents,bool is_capturing_window)66     virtual void OnIsCapturingWindowChanged(content::WebContents* web_contents,
67                                             bool is_capturing_window) {}
OnIsCapturingDisplayChanged(content::WebContents * web_contents,bool is_capturing_display)68     virtual void OnIsCapturingDisplayChanged(content::WebContents* web_contents,
69                                              bool is_capturing_display) {}
70 
71    protected:
72     ~Observer() override;
73   };
74 
75   MediaStreamCaptureIndicator();
76 
77   // Registers a new media stream for |web_contents| and returns an object used
78   // by the content layer to notify about the state of the stream. Optionally,
79   // |ui| is used to display custom UI while the stream is captured.
80   std::unique_ptr<content::MediaStreamUI> RegisterMediaStream(
81       content::WebContents* web_contents,
82       const blink::MediaStreamDevices& devices,
83       std::unique_ptr<MediaStreamUI> ui = nullptr);
84 
85   // Overrides from StatusIconMenuModel::Delegate implementation.
86   void ExecuteCommand(int command_id, int event_flags) override;
87 
88   // Returns true if |web_contents| is capturing user media (e.g., webcam or
89   // microphone input).
90   bool IsCapturingUserMedia(content::WebContents* web_contents) const;
91 
92   // Returns true if |web_contents| is capturing video (e.g., webcam).
93   bool IsCapturingVideo(content::WebContents* web_contents) const;
94 
95   // Returns true if |web_contents| is capturing audio (e.g., microphone).
96   bool IsCapturingAudio(content::WebContents* web_contents) const;
97 
98   // Returns true if |web_contents| itself is being mirrored (e.g., a source of
99   // media for remote broadcast).
100   bool IsBeingMirrored(content::WebContents* web_contents) const;
101 
102   // Returns true if |web_contents| is capturing a desktop window or audio.
103   bool IsCapturingWindow(content::WebContents* web_contents) const;
104 
105   // Returns true if |web_contents| is capturing a display.
106   bool IsCapturingDisplay(content::WebContents* web_contents) const;
107 
108   // Called when STOP button in media capture notification is clicked.
109   void NotifyStopped(content::WebContents* web_contents) const;
110 
111   // Adds/Removes observers. Observers needs to be removed during the lifetime
112   // of this object.
AddObserver(Observer * obs)113   void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
RemoveObserver(Observer * obs)114   void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
115 
116  private:
117   class UIDelegate;
118   class WebContentsDeviceUsage;
119   friend class WebContentsDeviceUsage;
120 
121   friend class base::RefCountedThreadSafe<MediaStreamCaptureIndicator>;
122   ~MediaStreamCaptureIndicator() override;
123 
124   // Following functions/variables are executed/accessed only on UI thread.
125 
126   // Called by WebContentsDeviceUsage when it's about to destroy itself, i.e.
127   // when WebContents is being destroyed.
128   void UnregisterWebContents(content::WebContents* web_contents);
129 
130   // Updates the status tray menu. Called by WebContentsDeviceUsage.
131   void UpdateNotificationUserInterface();
132 
133   // Helpers to create and destroy status tray icon. Called from
134   // UpdateNotificationUserInterface().
135   void EnsureStatusTrayIconResources();
136   void MaybeCreateStatusTrayIcon(bool audio, bool video);
137   void MaybeDestroyStatusTrayIcon();
138 
139   // Gets the status icon image and the string to use as the tooltip.
140   void GetStatusTrayIconInfo(bool audio,
141                              bool video,
142                              gfx::ImageSkia* image,
143                              base::string16* tool_tip);
144 
145   // Checks if |web_contents| or any portal WebContents in its tree is using
146   // a device for capture. The type of capture is specified using |pred|.
147   using WebContentsDeviceUsagePredicate =
148       base::RepeatingCallback<bool(const WebContentsDeviceUsage*)>;
149   bool CheckUsage(content::WebContents* web_contents,
150                   const WebContentsDeviceUsagePredicate& pred) const;
151 
152   // Reference to our status icon - owned by the StatusTray. If null,
153   // the platform doesn't support status icons.
154   StatusIcon* status_icon_ = nullptr;
155 
156   // A map that contains the usage counts of the opened capture devices for each
157   // WebContents instance.
158   std::unordered_map<content::WebContents*,
159                      std::unique_ptr<WebContentsDeviceUsage>>
160       usage_map_;
161 
162   // A vector which maps command IDs to their associated WebContents
163   // instance. This is rebuilt each time the status tray icon context menu is
164   // updated.
165   typedef std::vector<content::WebContents*> CommandTargets;
166   CommandTargets command_targets_;
167 
168   base::ObserverList<Observer, /* check_empty =*/true> observers_;
169 
170   DISALLOW_COPY_AND_ASSIGN(MediaStreamCaptureIndicator);
171 };
172 
173 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_CAPTURE_INDICATOR_H_
174