File: media_router_ui.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (361 lines) | stat: -rw-r--r-- 14,524 bytes parent folder | download | duplicates (6)
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_