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