mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-22 15:07:42 +01:00
Existing CefBrowserContext functionality is now split between CefBrowserContext and AlloyBrowserContext. Runtime implementations of CefBrowserContext will provide access to the content::BrowserContext and Profile types via different inheritance paths. For example, the Alloy runtime uses ChromeProfileAlloy and the Chrome runtime uses ProfileImpl. This change also renames CefResourceContext to CefIOThreadState to more accurately represent its purpose as it no longer needs to extend content::ResourceContext.
294 lines
9.7 KiB
C++
294 lines
9.7 KiB
C++
// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
|
|
// reserved. Use of this source code is governed by a BSD-style license that
|
|
// can be found in the LICENSE file.
|
|
|
|
#include "libcef/browser/media_router/media_router_manager.h"
|
|
|
|
#include "libcef/browser/browser_context.h"
|
|
#include "libcef/browser/thread_util.h"
|
|
|
|
#include "chrome/browser/media/router/media_router_factory.h"
|
|
#include "chrome/browser/media/router/media_routes_observer.h"
|
|
#include "chrome/browser/media/router/route_message_observer.h"
|
|
#include "chrome/browser/media/router/route_message_util.h"
|
|
|
|
namespace {
|
|
|
|
const int kTimeoutMs = 5 * 1000;
|
|
const char kDefaultPresentationUrl[] = "https://google.com";
|
|
|
|
} // namespace
|
|
|
|
class CefMediaRoutesObserver : public media_router::MediaRoutesObserver {
|
|
public:
|
|
explicit CefMediaRoutesObserver(CefMediaRouterManager* manager)
|
|
: media_router::MediaRoutesObserver(manager->GetMediaRouter()),
|
|
manager_(manager) {}
|
|
|
|
void OnRoutesUpdated(const std::vector<media_router::MediaRoute>& routes,
|
|
const std::vector<media_router::MediaRoute::Id>&
|
|
joinable_route_ids) override {
|
|
manager_->routes_ = routes;
|
|
manager_->NotifyCurrentRoutes();
|
|
}
|
|
|
|
private:
|
|
CefMediaRouterManager* const manager_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CefMediaRoutesObserver);
|
|
};
|
|
|
|
// Used to receive messages if PresentationConnection is not supported.
|
|
class CefRouteMessageObserver : public media_router::RouteMessageObserver {
|
|
public:
|
|
CefRouteMessageObserver(CefMediaRouterManager* manager,
|
|
const media_router::MediaRoute& route)
|
|
: media_router::RouteMessageObserver(manager->GetMediaRouter(),
|
|
route.media_route_id()),
|
|
manager_(manager),
|
|
route_(route) {}
|
|
|
|
void OnMessagesReceived(
|
|
CefMediaRouterManager::MediaMessageVector messages) override {
|
|
manager_->OnMessagesReceived(route_, messages);
|
|
}
|
|
|
|
private:
|
|
CefMediaRouterManager* const manager_;
|
|
const media_router::MediaRoute route_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CefRouteMessageObserver);
|
|
};
|
|
|
|
// Used for messaging and route status notifications with Cast.
|
|
class CefPresentationConnection : public blink::mojom::PresentationConnection {
|
|
public:
|
|
explicit CefPresentationConnection(
|
|
CefMediaRouterManager* manager,
|
|
const media_router::MediaRoute& route,
|
|
media_router::mojom::RoutePresentationConnectionPtr connections)
|
|
: manager_(manager),
|
|
route_(route),
|
|
connection_receiver_(this, std::move(connections->connection_receiver)),
|
|
connection_remote_(std::move(connections->connection_remote)) {}
|
|
|
|
void OnMessage(
|
|
blink::mojom::PresentationConnectionMessagePtr message) override {
|
|
CefMediaRouterManager::MediaMessageVector messages;
|
|
if (message->is_message()) {
|
|
messages.push_back(media_router::message_util::RouteMessageFromString(
|
|
message->get_message()));
|
|
} else if (message->is_data()) {
|
|
messages.push_back(media_router::message_util::RouteMessageFromData(
|
|
message->get_data()));
|
|
}
|
|
if (!messages.empty()) {
|
|
manager_->OnMessagesReceived(route_, messages);
|
|
}
|
|
}
|
|
|
|
void DidChangeState(
|
|
blink::mojom::PresentationConnectionState state) override {
|
|
// May result in |this| being deleted, so post async and allow the call
|
|
// stack to unwind.
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(&CefMediaRouterManager::OnRouteStateChange,
|
|
manager_->weak_ptr_factory_.GetWeakPtr(), route_,
|
|
content::PresentationConnectionStateChangeInfo(state)));
|
|
}
|
|
|
|
void DidClose(
|
|
blink::mojom::PresentationConnectionCloseReason reason) override {
|
|
DidChangeState(blink::mojom::PresentationConnectionState::CLOSED);
|
|
}
|
|
|
|
void SendRouteMessage(const std::string& message) {
|
|
connection_remote_->OnMessage(
|
|
blink::mojom::PresentationConnectionMessage::NewMessage(message));
|
|
}
|
|
|
|
private:
|
|
CefMediaRouterManager* const manager_;
|
|
const media_router::MediaRoute route_;
|
|
|
|
// Used to receive messages from the MRP.
|
|
mojo::Receiver<blink::mojom::PresentationConnection> connection_receiver_;
|
|
|
|
// Used to send messages to the MRP.
|
|
mojo::Remote<blink::mojom::PresentationConnection> connection_remote_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CefPresentationConnection);
|
|
};
|
|
|
|
CefMediaRouterManager::CefMediaRouterManager(
|
|
content::BrowserContext* browser_context)
|
|
: browser_context_(browser_context),
|
|
query_result_manager_(GetMediaRouter()),
|
|
weak_ptr_factory_(this) {
|
|
// Perform initialization.
|
|
GetMediaRouter()->OnUserGesture();
|
|
|
|
query_result_manager_.AddObserver(this);
|
|
|
|
// A non-empty presentation URL to required for discovery of Cast devices.
|
|
query_result_manager_.SetSourcesForCastMode(
|
|
media_router::MediaCastMode::PRESENTATION,
|
|
{media_router::MediaSource::ForPresentationUrl(
|
|
GURL(kDefaultPresentationUrl))},
|
|
url::Origin());
|
|
|
|
routes_observer_ = std::make_unique<CefMediaRoutesObserver>(this);
|
|
}
|
|
|
|
CefMediaRouterManager::~CefMediaRouterManager() {
|
|
CEF_REQUIRE_UIT();
|
|
for (auto& observer : observers_) {
|
|
observers_.RemoveObserver(&observer);
|
|
observer.OnMediaRouterDestroyed();
|
|
}
|
|
|
|
query_result_manager_.RemoveObserver(this);
|
|
}
|
|
|
|
void CefMediaRouterManager::AddObserver(Observer* observer) {
|
|
CEF_REQUIRE_UIT();
|
|
observers_.AddObserver(observer);
|
|
}
|
|
|
|
void CefMediaRouterManager::RemoveObserver(Observer* observer) {
|
|
CEF_REQUIRE_UIT();
|
|
observers_.RemoveObserver(observer);
|
|
}
|
|
|
|
void CefMediaRouterManager::NotifyCurrentSinks() {
|
|
CEF_REQUIRE_UIT();
|
|
for (auto& observer : observers_) {
|
|
observer.OnMediaSinks(sinks_);
|
|
}
|
|
}
|
|
|
|
void CefMediaRouterManager::NotifyCurrentRoutes() {
|
|
CEF_REQUIRE_UIT();
|
|
for (auto& observer : observers_) {
|
|
observer.OnMediaRoutes(routes_);
|
|
}
|
|
}
|
|
|
|
void CefMediaRouterManager::CreateRoute(
|
|
const media_router::MediaSource::Id& source_id,
|
|
const media_router::MediaSink::Id& sink_id,
|
|
const url::Origin& origin,
|
|
CreateRouteResultCallback callback) {
|
|
GetMediaRouter()->CreateRoute(
|
|
source_id, sink_id, origin, nullptr /* web_contents */,
|
|
base::BindOnce(&CefMediaRouterManager::OnCreateRoute,
|
|
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
|
|
base::TimeDelta::FromMilliseconds(kTimeoutMs), false /* incognito */);
|
|
}
|
|
|
|
void CefMediaRouterManager::SendRouteMessage(
|
|
const media_router::MediaRoute::Id& route_id,
|
|
const std::string& message) {
|
|
// Must use PresentationConnection to send messages if it exists.
|
|
auto state = GetRouteState(route_id);
|
|
if (state && state->presentation_connection_) {
|
|
state->presentation_connection_->SendRouteMessage(message);
|
|
return;
|
|
}
|
|
|
|
GetMediaRouter()->SendRouteMessage(route_id, message);
|
|
}
|
|
|
|
void CefMediaRouterManager::TerminateRoute(
|
|
const media_router::MediaRoute::Id& route_id) {
|
|
GetMediaRouter()->TerminateRoute(route_id);
|
|
}
|
|
|
|
void CefMediaRouterManager::OnResultsUpdated(const MediaSinkVector& sinks) {
|
|
sinks_ = sinks;
|
|
NotifyCurrentSinks();
|
|
}
|
|
|
|
media_router::MediaRouter* CefMediaRouterManager::GetMediaRouter() const {
|
|
CEF_REQUIRE_UIT();
|
|
return media_router::MediaRouterFactory::GetApiForBrowserContext(
|
|
browser_context_);
|
|
}
|
|
|
|
void CefMediaRouterManager::OnCreateRoute(
|
|
CreateRouteResultCallback callback,
|
|
media_router::mojom::RoutePresentationConnectionPtr connection,
|
|
const media_router::RouteRequestResult& result) {
|
|
CEF_REQUIRE_UIT();
|
|
if (result.route()) {
|
|
CreateRouteState(*result.route(), std::move(connection));
|
|
}
|
|
|
|
std::move(callback).Run(result);
|
|
}
|
|
|
|
void CefMediaRouterManager::OnRouteStateChange(
|
|
const media_router::MediaRoute& route,
|
|
const content::PresentationConnectionStateChangeInfo& info) {
|
|
CEF_REQUIRE_UIT();
|
|
if (info.state == blink::mojom::PresentationConnectionState::CLOSED ||
|
|
info.state == blink::mojom::PresentationConnectionState::TERMINATED) {
|
|
RemoveRouteState(route.media_route_id());
|
|
}
|
|
|
|
for (auto& observer : observers_) {
|
|
observer.OnMediaRouteStateChange(route, info);
|
|
}
|
|
}
|
|
|
|
void CefMediaRouterManager::OnMessagesReceived(
|
|
const media_router::MediaRoute& route,
|
|
const MediaMessageVector& messages) {
|
|
CEF_REQUIRE_UIT();
|
|
for (auto& observer : observers_) {
|
|
observer.OnMediaRouteMessages(route, messages);
|
|
}
|
|
}
|
|
|
|
void CefMediaRouterManager::CreateRouteState(
|
|
const media_router::MediaRoute& route,
|
|
media_router::mojom::RoutePresentationConnectionPtr connection) {
|
|
const auto route_id = route.media_route_id();
|
|
auto state = std::make_unique<RouteState>();
|
|
|
|
if (!connection.is_null()) {
|
|
// PresentationConnection must be used for messaging and status
|
|
// notifications if it exists.
|
|
state->presentation_connection_ =
|
|
std::make_unique<CefPresentationConnection>(this, route,
|
|
std::move(connection));
|
|
} else {
|
|
// Fallback if PresentationConnection is not supported.
|
|
state->message_observer_ =
|
|
std::make_unique<CefRouteMessageObserver>(this, route);
|
|
state->state_subscription_ =
|
|
GetMediaRouter()->AddPresentationConnectionStateChangedCallback(
|
|
route_id,
|
|
base::BindRepeating(&CefMediaRouterManager::OnRouteStateChange,
|
|
weak_ptr_factory_.GetWeakPtr(), route));
|
|
}
|
|
|
|
route_state_map_.insert(std::make_pair(route_id, std::move(state)));
|
|
}
|
|
|
|
CefMediaRouterManager::RouteState* CefMediaRouterManager::GetRouteState(
|
|
const media_router::MediaRoute::Id& route_id) {
|
|
const auto it = route_state_map_.find(route_id);
|
|
if (it != route_state_map_.end())
|
|
return it->second.get();
|
|
return nullptr;
|
|
}
|
|
|
|
void CefMediaRouterManager::RemoveRouteState(
|
|
const media_router::MediaRoute::Id& route_id) {
|
|
auto it = route_state_map_.find(route_id);
|
|
if (it != route_state_map_.end())
|
|
route_state_map_.erase(it);
|
|
}
|