File: dial_media_sink_service_impl.h

package info (click to toggle)
chromium 139.0.7258.127-1~deb13u1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,096 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 (200 lines) | stat: -rw-r--r-- 8,658 bytes parent folder | download | duplicates (7)
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
// Copyright 2017 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_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_MEDIA_SINK_SERVICE_IMPL_H_
#define CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_MEDIA_SINK_SERVICE_IMPL_H_

#include <memory>
#include <set>

#include "base/containers/flat_map.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/media/router/discovery/dial/device_description_service.h"
#include "chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h"
#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service.h"
#include "chrome/browser/media/router/discovery/dial/dial_registry.h"
#include "chrome/browser/media/router/discovery/media_sink_discovery_metrics.h"
#include "components/media_router/common/discovery/media_sink_service_base.h"
#include "components/media_router/common/discovery/media_sink_service_util.h"

namespace media_router {

class DeviceDescriptionService;
class DialRegistry;

// A service which can be used to start background discovery and resolution of
// DIAL devices (Smart TVs, Game Consoles, etc.). It is indirectly owned by a
// singleton that is never freed. It may be created on any thread. All methods,
// unless otherwise noted, must be invoked on the SequencedTaskRunner given by
// |task_runner()|.
class DialMediaSinkServiceImpl : public MediaSinkServiceBase,
                                 public DialRegistry::Client {
 public:
  // Callbacks invoked when the list of available sinks for |app_name| changes.
  // The client can call |GetAvailableSinks()| to obtain the latest sink list.
  // |app_name|: app name, e.g. YouTube.
  // TODO(imcheng): Move sink query logic into DialAppDiscoveryService and
  // have it use MediaSinkServiceBase::Observer to observe sinks.
  using SinkQueryByAppCallbackList =
      base::RepeatingCallbackList<void(const std::string&)>;
  using SinkQueryByAppCallback = SinkQueryByAppCallbackList::CallbackType;

  // Represents DIAL app status on receiver device.
  enum SinkAppStatus { kUnknown = 0, kAvailable, kUnavailable };

  // |on_sinks_discovered_cb|: Callback for MediaSinkServiceBase.
  // Note that both callbacks are invoked on |task_runner|.
  // |task_runner|: The SequencedTaskRunner this class runs in.
  DialMediaSinkServiceImpl(
      const OnSinksDiscoveredCallback& on_sinks_discovered_cb,
      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
  ~DialMediaSinkServiceImpl() override;

  virtual void Initialize();

  void StartDiscovery();

  // MediaSinkServiceBase implementation.
  void DiscoverSinksNow() override;

  // Returns the SequencedTaskRunner that should be used to invoke methods on
  // this instance. Can be invoked on any thread.
  scoped_refptr<base::SequencedTaskRunner> task_runner() {
    return task_runner_;
  }

  virtual DialAppDiscoveryService* app_discovery_service();

  // Registers |callback| to callback list entry in |sink_queries_|, with the
  // key |app_name|. Caller owns the returned subscription and is responsible
  // for destroying when it wants to unregister |callback|. Marked virtual for
  // tests.
  virtual base::CallbackListSubscription StartMonitoringAvailableSinksForApp(
      const std::string& app_name,
      const SinkQueryByAppCallback& callback);

  // Returns the current list of sinks compatible with |app_name|. The caller
  // can call this method after calling |StartMonitoringAvailableSinksForApp()|
  // to obtain the initial list, or when the callback fires to get the updated
  // list.
  // Marked virtual for tests.
  virtual std::vector<MediaSinkInternal> GetAvailableSinks(
      const std::string& app_name) const;

 protected:
  void SetDescriptionServiceForTest(
      std::unique_ptr<DeviceDescriptionService> description_service);
  void SetAppDiscoveryServiceForTest(
      std::unique_ptr<DialAppDiscoveryService> app_discovery_service);

 private:
  friend class DialMediaSinkServiceImplTest;
  friend class MockDialMediaSinkServiceImpl;
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDeviceDescriptionRestartsTimer);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialDeviceListRestartsTimer);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDeviceDescriptionAvailable);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDeviceDescriptionAvailableIPAddressChanged);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           StartStopMonitoringAvailableSinksForApp);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialAppInfoAvailableNoStartMonitoring);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialAppInfoAvailableNoSink);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialAppInfoAvailableSinksAdded);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialAppInfoAvailableSinksRemoved);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           OnDialAppInfoAvailableWithAlreadyAvailableSinks);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           StartAfterStopMonitoringForApp);
  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                           FetchDialAppInfoWithDiscoveryOnlySink);

  // DialRegistry::Client implementation
  void OnDialDeviceList(const DialRegistry::DeviceList& devices) override;
  void OnDialError(DialRegistry::DialErrorCode type) override;

  // Called when description service successfully fetches and parses device
  // description XML. Restart |finish_timer_| if it is not running.
  void OnDeviceDescriptionAvailable(
      const DialDeviceData& device_data,
      const ParsedDialDeviceDescription& description_data);

  // Called when fails to fetch or parse device description XML.
  void OnDeviceDescriptionError(const DialDeviceData& device,
                                const std::string& error_message);

  // Called when app discovery service finishes fetching and parsing app info
  // XML.
  void OnAppInfoParseCompleted(const std::string& sink_id,
                               const std::string& app_name,
                               DialAppInfoResult result);

  // Queries app status of |app_name| on |dial_sink|.
  void FetchAppInfoForSink(const MediaSinkInternal& dial_sink,
                           const std::string& app_name);

  // Issues HTTP request to get status of all registered apps on current sinks.
  void RescanAppInfo();

  // Helper function to get app status from |app_statuses_|.
  SinkAppStatus GetAppStatus(const std::string& sink_id,
                             const std::string& app_name) const;

  // Helper function to set app status in |app_statuses_|.
  void SetAppStatus(const std::string& sink_id,
                    const std::string& app_name,
                    SinkAppStatus app_status);

  void MaybeRemoveSinkQueryCallbackList(
      const std::string& app_name,
      SinkQueryByAppCallbackList* callback_list);

  // MediaSinkServiceBase implementation.
  void OnDiscoveryComplete() override;
  void RecordDeviceCounts() override;

  // Initialized in |Start()|.
  std::unique_ptr<DialRegistry> dial_registry_;

  // Initialized in |Start()|.
  std::unique_ptr<DeviceDescriptionService> description_service_;

  // Initialized in |Start()|.
  std::unique_ptr<DialAppDiscoveryService> app_discovery_service_;

  // Device data list from current round of discovery.
  DialRegistry::DeviceList current_devices_;

  // Sinks that are added during the latest round of discovery. In
  // |OnDiscoveryCompleted()| this will be merged into
  // |MediaSinkServiceBase::sinks_| and then cleared.
  base::flat_map<MediaSink::Id, MediaSinkInternal> latest_sinks_;

  // Map of app status, keyed by <sink id:app name>.
  base::flat_map<std::string, SinkAppStatus> app_statuses_;

  // Set of sink queries keyed by app name.
  base::flat_map<std::string, std::unique_ptr<SinkQueryByAppCallbackList>>
      sink_queries_;

  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  DialDeviceCountMetrics metrics_;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace media_router

#endif  // CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_MEDIA_SINK_SERVICE_IMPL_H_