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
|
// 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_MEDIA_ROUTER_PROVIDERS_DIAL_DIAL_MEDIA_ROUTE_PROVIDER_H_
#define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_DIAL_DIAL_MEDIA_ROUTE_PROVIDER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h"
#include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
#include "chrome/browser/media/router/providers/dial/dial_internal_message_util.h"
#include "components/media_router/common/mojom/media_router.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
namespace url {
class Origin;
}
namespace media_router {
// MediaRouteProvider for DIAL sinks.
// DialMediaRouteProvider supports custom DIAL launch, which is a
// way for websites that uses Cast SDK to launch apps on DIAL devices.
// The life of a custom DIAL launch workflow is as follows:
// 1) The user initiates a custom DIAL launch by selecting a DIAL device
// to cast to. This becomes a CreateRoute request to the
// DialMediaRouteProvider.
// 2) The DialMediaRouteProvider sends NEW_SESSION / RECEIVER_ACTION messages to
// the Cast SDK to inform of a new Cast session. In addition, a
// CUSTOM_DIAL_LAUNCH request is sent to the Cast SDK.
// 3) The Cast SDK sends back a CUSTOM_DIAL_LAUNCH response. Depending on the
// response, either the page have already handled the app launch, or the
// DialMediaRouteProvider will initiate the app launch on the device.
// 4) Once the app is launched, the workflow is complete. The webpage will then
// communicate with the app on the device via its own mechanism.
class DialMediaRouteProvider : public mojom::MediaRouteProvider,
public MediaSinkServiceBase::Observer {
public:
// |receiver|: Mojo receiver to bind to |this|.
// |media_router|: Pending remote to MediaRouter.
// |media_sink_service|: DIAL MediaSinkService providing information on sinks.
// |hash_token|: A per-profile value used to hash sink IDs.
// |task_runner|: The task runner on which |this| runs.
DialMediaRouteProvider(
mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
mojo::PendingRemote<mojom::MediaRouter> media_router,
DialMediaSinkServiceImpl* media_sink_service,
const std::string& hash_token,
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
DialMediaRouteProvider(const DialMediaRouteProvider&) = delete;
DialMediaRouteProvider& operator=(const DialMediaRouteProvider&) = delete;
~DialMediaRouteProvider() override;
// mojom::MediaRouteProvider:
void CreateRoute(const std::string& media_source,
const std::string& sink_id,
const std::string& presentation_id,
const url::Origin& origin,
int32_t frame_tree_node_id,
base::TimeDelta timeout,
CreateRouteCallback callback) override;
void JoinRoute(const std::string& media_source,
const std::string& presentation_id,
const url::Origin& origin,
int32_t frame_tree_node_id,
base::TimeDelta timeout,
JoinRouteCallback callback) override;
void TerminateRoute(const std::string& route_id,
TerminateRouteCallback callback) override;
void SendRouteMessage(const std::string& media_route_id,
const std::string& message) override;
void SendRouteBinaryMessage(const std::string& media_route_id,
const std::vector<uint8_t>& data) override;
void StartObservingMediaSinks(const std::string& media_source) override;
void StopObservingMediaSinks(const std::string& media_source) override;
void StartObservingMediaRoutes() override;
void DetachRoute(const std::string& route_id) override;
void DiscoverSinksNow() override;
void BindMediaController(
const std::string& route_id,
mojo::PendingReceiver<mojom::MediaController> media_controller,
mojo::PendingRemote<mojom::MediaStatusObserver> observer,
BindMediaControllerCallback callback) override;
void GetState(GetStateCallback callback) override;
void SetActivityManagerForTest(
std::unique_ptr<DialActivityManager> activity_manager);
private:
FRIEND_TEST_ALL_PREFIXES(DialMediaRouteProviderTest, AddRemoveSinkQuery);
FRIEND_TEST_ALL_PREFIXES(DialMediaRouteProviderTest,
AddSinkQuerySameMediaSource);
FRIEND_TEST_ALL_PREFIXES(DialMediaRouteProviderTest,
AddSinkQuerySameAppDifferentMediaSources);
FRIEND_TEST_ALL_PREFIXES(DialMediaRouteProviderTest,
AddSinkQueryDifferentApps);
FRIEND_TEST_ALL_PREFIXES(DialMediaRouteProviderTest, ListenForRouteMessages);
struct MediaSinkQuery {
MediaSinkQuery();
MediaSinkQuery(const MediaSinkQuery&) = delete;
MediaSinkQuery& operator=(const MediaSinkQuery&) = delete;
~MediaSinkQuery();
// Set of registered media sources for current sink query.
base::flat_set<MediaSource> media_sources;
base::CallbackListSubscription subscription;
};
// MediaSinkServiceBase::Observer:
void OnSinksDiscovered(const std::vector<MediaSinkInternal>& sinks) override;
// Binds the message pipes |receiver| and |media_router| to |this|.
void Init(mojo::PendingReceiver<mojom::MediaRouteProvider> receiver,
mojo::PendingRemote<mojom::MediaRouter> media_router);
void OnAvailableSinksUpdated(const std::string& app_name);
void NotifyOnSinksReceived(const MediaSource::Id& source_id,
const std::vector<MediaSinkInternal>& sinks,
const std::vector<url::Origin>& origins);
void HandleParsedRouteMessage(const MediaRoute::Id& route_id,
data_decoder::DataDecoder::ValueOrError result);
void HandleClientConnect(const DialActivity& activity,
const MediaSinkInternal& sink);
void SendCustomDialLaunchMessage(const MediaRoute::Id& route_id,
const MediaSink::Id& sink_id,
const std::string& app_name,
DialAppInfoResult result);
void SendDialAppInfoResponse(const MediaRoute::Id& route_id,
int sequence_number,
const MediaSink::Id& sink_id,
const std::string& app_name,
DialAppInfoResult result);
void HandleCustomDialLaunchResponse(const DialActivity& activity,
const DialInternalMessage& message);
void HandleDiapAppInfoRequest(const DialActivity& activity,
const DialInternalMessage& message,
const MediaSinkInternal& sink);
void HandleAppLaunchResult(const MediaRoute::Id& route_id, bool success);
void DoTerminateRoute(const DialActivity& activity,
const MediaSinkInternal& sink,
TerminateRouteCallback callback);
void HandleStopAppResult(const MediaRoute::Id& route_id,
TerminateRouteCallback callback,
const std::optional<std::string>& message,
mojom::RouteRequestResultCode result_code);
void NotifyAllOnRoutesUpdated();
void NotifyOnRoutesUpdated(const std::vector<MediaRoute>& routes);
// Returns a list of valid origins for |app_name|. Returns an empty list if
// all origins are valid.
std::vector<url::Origin> GetOrigins(const std::string& app_name);
// Binds |this| to the Mojo receiver passed into the ctor.
mojo::Receiver<mojom::MediaRouteProvider> receiver_{this};
// Mojo remote to the Media Router.
mojo::Remote<mojom::MediaRouter> media_router_;
// Non-owned pointer to the DialMediaSinkServiceImpl instance.
const raw_ptr<DialMediaSinkServiceImpl> media_sink_service_;
// Map of media sink queries, keyed by app name.
base::flat_map<std::string, std::unique_ptr<MediaSinkQuery>>
media_sink_queries_;
// Set of route queries by MediaSource ID.
base::flat_set<MediaSource::Id> media_route_queries_;
// Set of pending DIAL launches by sequence number. The max number of pending
// launches is capped, and oldest entries (smallest number) will be evicted.
base::flat_set<int> pending_dial_launches_;
std::unique_ptr<DialActivityManager> activity_manager_;
DialInternalMessageUtil internal_message_util_;
// Mojo remote to the logger owned by the Media Router.
mojo::Remote<mojom::Logger> logger_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<DialMediaRouteProvider> weak_ptr_factory_{this};
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_DIAL_DIAL_MEDIA_ROUTE_PROVIDER_H_
|