1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
#define CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
#include <set>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
#include "chrome/browser/ui/media_router/cast_dialog_model.h"
#include "chrome/browser/ui/media_router/media_cast_mode.h"
#include "chrome/browser/ui/media_router/media_route_starter.h"
#include "chrome/browser/ui/media_router/media_router_ui_helper.h"
#include "chrome/browser/ui/media_router/media_sink_with_cast_modes.h"
#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h"
#include "chrome/browser/ui/media_router/presentation_request_source_observer.h"
#include "components/media_router/browser/issues_observer.h"
#include "components/media_router/browser/media_router_dialog_controller.h"
#include "components/media_router/browser/mirroring_media_controller_host.h"
#include "components/media_router/common/issue.h"
#include "components/media_router/common/media_source.h"
namespace content {
struct PresentationRequest;
class WebContents;
} // namespace content
namespace U_ICU_NAMESPACE {
class Collator;
}
namespace media_router {
class MediaRoute;
class MediaRouter;
class MediaRoutesObserver;
class MediaSink;
class RouteRequestResult;
class WebContentsDisplayObserver;
// Functions as an intermediary between MediaRouter and Views Cast dialog.
class MediaRouterUI : public CastDialogController,
public MediaSinkWithCastModesObserver,
public PresentationRequestSourceObserver,
public MirroringMediaControllerHost::Observer {
public:
// MediaRouterUI's are typically created with one of the CreateWith* methods
// below.
explicit MediaRouterUI(
std::unique_ptr<MediaRouteStarter> media_route_starter);
MediaRouterUI(const MediaRouterUI&) = delete;
MediaRouterUI& operator=(const MediaRouterUI&) = delete;
~MediaRouterUI() override;
// Creates a |MediaRouterUI| (e.g. starts listening for MediaSinks) for
// targeting the default MediaSource (if any) of |initiator|. The contents
// of the UI will change as the default MediaSource changes. If there is a
// default MediaSource, then PRESENTATION MediaCastMode will be added to
// |cast_modes_|.
static std::unique_ptr<MediaRouterUI> CreateWithDefaultMediaSource(
content::WebContents* initiator);
// Initializes mirroring sources of the tab in addition to what is done by
// |CreateWithDefaultMediaSource()|.
static std::unique_ptr<MediaRouterUI>
CreateWithDefaultMediaSourceAndMirroring(content::WebContents* initiator);
// Initializes internal state targeting the presentation specified in
// |context|. This is different from CreateWithDefaultMediaSource*() in that
// it does not listen for default media source changes, as the UI is fixed to
// the source in |context|. Init* methods can only be called once.
// |context|: Context object for the PresentationRequest. This instance will
// take ownership of it. Must not be null.
static std::unique_ptr<MediaRouterUI> CreateWithStartPresentationContext(
content::WebContents* initiator,
std::unique_ptr<StartPresentationContext> context);
// Initializes mirroring sources of the tab in addition to what is done by
// |CreateWithStartPresentationContext()|.
static std::unique_ptr<MediaRouterUI>
CreateWithStartPresentationContextAndMirroring(
content::WebContents* initiator,
std::unique_ptr<StartPresentationContext> context);
// Initializes RemotePlayback source only.
static std::unique_ptr<MediaRouterUI> CreateWithMediaSessionRemotePlayback(
content::WebContents* initiator,
media::VideoCodec video_codec,
media::AudioCodec audio_codec);
// CastDialogController:
void AddObserver(CastDialogController::Observer* observer) override;
void RemoveObserver(CastDialogController::Observer* observer) override;
void StartCasting(const std::string& sink_id,
MediaCastMode cast_mode) override;
void StopCasting(const std::string& route_id) override;
void ClearIssue(const Issue::Id& issue_id) override;
void FreezeRoute(const std::string& route_id) override;
void UnfreezeRoute(const std::string& route_id) override;
// Note that |MediaRouterUI| should not be used after |TakeMediaRouteStarter|
// is called. To enforce that, |TakeMediaRouteStarter| calls the destructor
// callback given to |RegisterDestructor| to destroy itself.
std::unique_ptr<MediaRouteStarter> TakeMediaRouteStarter() override;
void RegisterDestructor(base::OnceClosure destructor) override;
// Requests a route be created from the source mapped to
// |cast_mode|, to the sink given by |sink_id|.
// Returns true if a route request is successfully submitted.
// |OnRouteResponseReceived()| will be invoked when the route request
// completes.
virtual bool CreateRoute(const MediaSink::Id& sink_id,
MediaCastMode cast_mode);
// Calls MediaRouter to terminate the given route.
void TerminateRoute(const MediaRoute::Id& route_id);
// Returns a subset of |sinks_| that should be listed in the dialog. This
// excludes the wired display that the initiator WebContents is on.
// Also filters cloud sinks in incognito windows.
std::vector<MediaSinkWithCastModes> GetEnabledSinks() const;
// Calls MediaRouter to add the given issue.
void AddIssue(const IssueInfo& issue);
// Calls MediaRouter to remove the given issue.
void RemoveIssue(const Issue::Id& issue_id);
// Uses LoggerImpl to log current available sinks.
void LogMediaSinkStatus();
const std::vector<MediaRoute>& routes() const { return routes_; }
content::WebContents* initiator() const {
return media_route_starter()->GetWebContents();
}
private:
friend class MediaRouterViewsUITest;
friend class MediaRouterCastUiForTest;
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, SetDialogHeader);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest,
UpdateSinksWhenDialogMovesToAnotherDisplay);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, NotifyObserver);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, SinkFriendlyName);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, ConnectingState);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, DisconnectingState);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, AddAndRemoveIssue);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, ShowDomainForHangouts);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUIIncognitoTest,
HidesCloudSinksForIncognito);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, RouteCreationTimeout);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest,
RouteCreationTimeoutIssueTitle);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest,
DesktopMirroringFailsWhenDisallowedOnMac);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest,
RouteCreationLocalFileModeInTab);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
UIMediaRoutesObserverAssignsCurrentCastModes);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
UIMediaRoutesObserverSkipsUnavailableCastModes);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
UpdateSinksWhenDialogMovesToAnotherDisplay);
FRIEND_TEST_ALL_PREFIXES(MediaRouterViewsUITest, OnFreezeInfoChanged);
class WebContentsFullscreenOnLoadedObserver;
// This class calls to refresh the UI when the highest priority issue is
// updated.
class UiIssuesObserver : public IssuesObserver {
public:
UiIssuesObserver(IssueManager* issue_manager, MediaRouterUI* ui);
UiIssuesObserver(const UiIssuesObserver&) = delete;
UiIssuesObserver& operator=(const UiIssuesObserver&) = delete;
~UiIssuesObserver() override;
// IssuesObserver:
void OnIssue(const Issue& issue) override;
void OnIssuesCleared() override;
private:
// Reference back to the owning MediaRouterUI instance.
const raw_ptr<MediaRouterUI> ui_;
};
class UIMediaRoutesObserver : public MediaRoutesObserver {
public:
using RoutesUpdatedCallback =
base::RepeatingCallback<void(const std::vector<MediaRoute>&)>;
UIMediaRoutesObserver(MediaRouter* router,
const RoutesUpdatedCallback& callback);
UIMediaRoutesObserver(const UIMediaRoutesObserver&) = delete;
UIMediaRoutesObserver& operator=(const UIMediaRoutesObserver&) = delete;
~UIMediaRoutesObserver() override;
// MediaRoutesObserver:
void OnRoutesUpdated(const std::vector<MediaRoute>& routes) override;
private:
// Callback to the owning MediaRouterUI instance.
RoutesUpdatedCallback callback_;
};
virtual void Init();
// Removes |MediaRouteStarter| listeners and alerts observers that this
// controller is now invalid.
void DetachFromMediaRouteStarter();
// PresentationRequestSourceObserver
void OnSourceUpdated(std::u16string& source_name) override;
// MirroringObserver
void OnFreezeInfoChanged() override;
// Called to update the dialog with the current list of of enabled sinks.
void UpdateSinks();
std::u16string GetSinkFriendlyNameFromId(const MediaSink::Id& sink_id);
// Creates and sends an issue if route creation timed out.
void SendIssueForRouteTimeout(
MediaCastMode cast_mode,
const MediaSink::Id& sink_id,
const std::u16string& presentation_request_source_name);
// Creates and sends an issue if casting fails due to lack of screen
// permissions.
void SendIssueForScreenPermission(const MediaSink::Id& sink_id);
// Creates and sends an issue if casting fails for any reason other than
// those above.
void SendIssueForUnableToCast(MediaCastMode cast_mode,
const MediaSink::Id& sink_id);
// Creates and sends an issue for notifying the user that the tab audio cannot
// be mirrored from their device.
void SendIssueForTabAudioNotSupported(const MediaSink::Id& sink_id);
// Creates and sends an issue when the user rejects the Cast request on the
// receiver device.
void SendIssueForUserNotAllowed(const MediaSink::Id& sink_id);
// Creates and send an issue when casting did not start because notifications
// are disabled on the receiver device.
void SendIssueForNotificationDisabled(const MediaSink::Id& sink_id);
// Returns the IssueManager associated with |router_|.
IssueManager* GetIssueManager();
// Instantiates and initializes the issues observer.
void StartObservingIssues();
void OnIssue(const Issue& issue);
void OnIssueCleared();
// Called by |routes_observer_| when the set of active routes has changed.
void OnRoutesUpdated(const std::vector<MediaRoute>& routes);
// MediaSinkWithCastModesObserver:
void OnSinksUpdated(
const std::vector<MediaSinkWithCastModes>& sinks) override;
// Callback passed to MediaRouter to receive response to route creation
// requests.
virtual void OnRouteResponseReceived(
int route_request_id,
const MediaSink::Id& sink_id,
MediaCastMode cast_mode,
const std::u16string& presentation_request_source_name,
const RouteRequestResult& result);
// Update the header text in the dialog model and notify observers.
void UpdateModelHeader(const std::u16string& source_name);
UIMediaSink ConvertToUISink(const MediaSinkWithCastModes& sink,
const MediaRoute* route,
const std::optional<Issue>& issue);
void StopObservingMirroringMediaControllerHosts();
// Returns the MediaRouter for this instance's BrowserContext.
virtual MediaRouter* GetMediaRouter() const;
const std::optional<RouteRequest> current_route_request() const {
return current_route_request_;
}
MediaRouteStarter* media_route_starter() const {
DCHECK(media_route_starter_)
<< "can't call media_route_starter() after TakeMediaRouteStarter()!";
return media_route_starter_.get();
}
// Helper factory that creates both the |MediaRouteStarter| and then a
// |MediaRouterUI| in a single step.
static std::unique_ptr<MediaRouterUI> CreateMediaRouterUI(
MediaRouterUIParameters params);
raw_ptr<content::WebContentsObserver> web_contents_observer_for_test_ =
nullptr;
// This value is set whenever there is an outstanding issue.
std::optional<Issue> issue_;
// Contains up-to-date data to show in the dialog.
CastDialogModel model_;
// This value is set when the UI requests a route to be terminated, and gets
// reset when the route is removed.
std::optional<MediaRoute::Id> terminating_route_id_;
// Observers for dialog model updates.
// TODO(takumif): CastDialogModel should manage the observers.
base::ObserverList<CastDialogController::Observer>::Unchecked observers_;
// This is non-null while this instance is registered to receive
// updates from them.
std::unique_ptr<MediaRoutesObserver> routes_observer_;
// This contains a value only when tracking a pending route request.
std::optional<RouteRequest> current_route_request_;
// Used for locale-aware sorting of sinks by name. Set during
// Init() using the current locale.
std::unique_ptr<icu::Collator> collator_;
std::vector<MediaSinkWithCastModes> sinks_;
std::vector<MediaRoute> routes_;
std::unique_ptr<MediaRouteStarter> media_route_starter_;
std::unique_ptr<IssuesObserver> issues_observer_;
// Keeps track of which display the initiator WebContents is on. This is used
// to make sure we don't show a wired display presentation over the
// controlling window.
std::unique_ptr<WebContentsDisplayObserver> display_observer_;
raw_ptr<MediaRouter> router_;
raw_ptr<LoggerImpl> logger_;
base::OnceClosure destructor_;
// NOTE: Weak pointers must be invalidated before all other member variables.
// Therefore |weak_factory_| must be placed at the end.
base::WeakPtrFactory<MediaRouterUI> weak_factory_{this};
};
} // namespace media_router
#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
|