blob: dff488624e97b98910c7019be6f0853bfa4595dc [file] [log] [blame]
// Copyright 2015 The Chromium 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 "chrome/browser/media/router/mojo/media_router_mojo_impl.h"
#include <stddef.h>
#include <utility>
#include "base/bind.h"
#include "base/guid.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/observer_list.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_proxy.h"
#include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h"
#include "chrome/browser/media/router/issues_observer.h"
#include "chrome/browser/media/router/media_router_factory.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/media/router/media_routes_observer.h"
#include "chrome/browser/media/router/media_sinks_observer.h"
#include "chrome/browser/media/router/mojo/media_route_controller.h"
#include "chrome/browser/media/router/mojo/media_route_provider_util_win.h"
#include "chrome/browser/media/router/mojo/media_router_mojo_metrics.h"
#include "chrome/browser/media/router/route_message_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/common/media_router/media_source_helper.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/presentation_connection_message.h"
#define DVLOG_WITH_INSTANCE(level) \
DVLOG(level) << "MR #" << instance_id_ << ": "
#define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": "
namespace media_router {
namespace {
void RunRouteRequestCallbacks(
std::unique_ptr<RouteRequestResult> result,
std::vector<MediaRouteResponseCallback> callbacks) {
for (MediaRouteResponseCallback& callback : callbacks)
std::move(callback).Run(*result);
}
} // namespace
using SinkAvailability = mojom::MediaRouter::SinkAvailability;
MediaRouterMojoImpl::MediaRoutesQuery::MediaRoutesQuery() = default;
MediaRouterMojoImpl::MediaRoutesQuery::~MediaRoutesQuery() = default;
MediaRouterMojoImpl::MediaSinksQuery::MediaSinksQuery() = default;
MediaRouterMojoImpl::MediaSinksQuery::~MediaSinksQuery() = default;
MediaRouterMojoImpl::MediaRouterMojoImpl(content::BrowserContext* context)
: instance_id_(base::GenerateGUID()),
availability_(mojom::MediaRouter::SinkAvailability::UNAVAILABLE),
context_(context),
weak_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
MediaRouterMojoImpl::~MediaRouterMojoImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (dial_media_sink_service_proxy_) {
dial_media_sink_service_proxy_->Stop();
dial_media_sink_service_proxy_->ClearObserver(
cast_media_sink_service_.get());
}
if (cast_media_sink_service_)
cast_media_sink_service_->Stop();
}
void MediaRouterMojoImpl::OnConnectionError() {}
void MediaRouterMojoImpl::RegisterMediaRouteProvider(
mojom::MediaRouteProviderPtr media_route_provider_ptr,
mojom::MediaRouter::RegisterMediaRouteProviderCallback callback) {}
void MediaRouterMojoImpl::OnIssue(const IssueInfo& issue) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue.title;
issue_manager_.AddIssue(issue);
}
void MediaRouterMojoImpl::OnSinksReceived(
const std::string& media_source,
const std::vector<MediaSinkInternal>& internal_sinks,
const std::vector<url::Origin>& origins) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "OnSinksReceived";
auto it = sinks_queries_.find(media_source);
if (it == sinks_queries_.end()) {
DVLOG_WITH_INSTANCE(1) << "Received sink list without MediaSinksQuery.";
return;
}
std::vector<MediaSink> sinks;
sinks.reserve(internal_sinks.size());
for (const auto& internal_sink : internal_sinks)
sinks.push_back(internal_sink.sink());
auto* sinks_query = it->second.get();
sinks_query->cached_sink_list = sinks;
sinks_query->origins = origins;
if (sinks_query->observers.might_have_observers()) {
for (auto& observer : sinks_query->observers) {
observer.OnSinksUpdated(*sinks_query->cached_sink_list,
sinks_query->origins);
}
} else {
DVLOG_WITH_INSTANCE(1)
<< "Received sink list without any active observers: " << media_source;
}
}
void MediaRouterMojoImpl::OnRoutesUpdated(
const std::vector<MediaRoute>& routes,
const std::string& media_source,
const std::vector<std::string>& joinable_route_ids) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "OnRoutesUpdated";
auto it = routes_queries_.find(media_source);
if (it == routes_queries_.end() ||
!(it->second->observers.might_have_observers())) {
DVLOG_WITH_INSTANCE(1)
<< "Received route list without any active observers: " << media_source;
return;
}
auto* routes_query = it->second.get();
routes_query->cached_route_list = routes;
routes_query->joinable_route_ids = joinable_route_ids;
if (routes_query->observers.might_have_observers()) {
for (auto& observer : routes_query->observers)
observer.OnRoutesUpdated(routes, joinable_route_ids);
} else {
DVLOG_WITH_INSTANCE(1)
<< "Received routes update without any active observers: "
<< media_source;
}
RemoveInvalidRouteControllers(routes);
}
void MediaRouterMojoImpl::RouteResponseReceived(
const std::string& presentation_id,
bool is_incognito,
std::vector<MediaRouteResponseCallback> callbacks,
bool is_join,
const base::Optional<MediaRoute>& media_route,
const base::Optional<std::string>& error_text,
RouteRequestResult::ResultCode result_code) {
std::unique_ptr<RouteRequestResult> result;
if (!media_route) {
// An error occurred.
const std::string& error = (error_text && !error_text->empty())
? *error_text : std::string("Unknown error.");
result = RouteRequestResult::FromError(error, result_code);
} else if (media_route->is_incognito() != is_incognito) {
std::string error = base::StringPrintf(
"Mismatch in incognito status: request = %d, response = %d",
is_incognito, media_route->is_incognito());
result = RouteRequestResult::FromError(
error, RouteRequestResult::INCOGNITO_MISMATCH);
} else {
result =
RouteRequestResult::FromSuccess(media_route.value(), presentation_id);
}
if (is_join)
MediaRouterMojoMetrics::RecordJoinRouteResultCode(result->result_code());
else
MediaRouterMojoMetrics::RecordCreateRouteResultCode(result->result_code());
RunRouteRequestCallbacks(std::move(result), std::move(callbacks));
}
void MediaRouterMojoImpl::CreateRoute(
const MediaSource::Id& source_id,
const MediaSink::Id& sink_id,
const url::Origin& origin,
content::WebContents* web_contents,
std::vector<MediaRouteResponseCallback> callbacks,
base::TimeDelta timeout,
bool incognito) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
int tab_id = SessionTabHelper::IdForTab(web_contents);
std::string presentation_id = MediaRouterBase::CreatePresentationId();
auto callback = base::BindOnce(&MediaRouterMojoImpl::RouteResponseReceived,
weak_factory_.GetWeakPtr(), presentation_id,
incognito, base::Passed(&callbacks), false);
media_route_provider_->CreateRoute(source_id, sink_id, presentation_id,
origin, tab_id, timeout, incognito,
std::move(callback));
}
void MediaRouterMojoImpl::JoinRoute(
const MediaSource::Id& source_id,
const std::string& presentation_id,
const url::Origin& origin,
content::WebContents* web_contents,
std::vector<MediaRouteResponseCallback> callbacks,
base::TimeDelta timeout,
bool incognito) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!HasJoinableRoute()) {
DVLOG_WITH_INSTANCE(1) << "No joinable routes";
std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError(
"Route not found", RouteRequestResult::ROUTE_NOT_FOUND);
MediaRouterMojoMetrics::RecordJoinRouteResultCode(result->result_code());
RunRouteRequestCallbacks(std::move(result), std::move(callbacks));
return;
}
int tab_id = SessionTabHelper::IdForTab(web_contents);
auto callback = base::BindOnce(&MediaRouterMojoImpl::RouteResponseReceived,
weak_factory_.GetWeakPtr(), presentation_id,
incognito, base::Passed(&callbacks), true);
media_route_provider_->JoinRoute(source_id, presentation_id, origin, tab_id,
timeout, incognito, std::move(callback));
}
void MediaRouterMojoImpl::ConnectRouteByRouteId(
const MediaSource::Id& source_id,
const MediaRoute::Id& route_id,
const url::Origin& origin,
content::WebContents* web_contents,
std::vector<MediaRouteResponseCallback> callbacks,
base::TimeDelta timeout,
bool incognito) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
int tab_id = SessionTabHelper::IdForTab(web_contents);
std::string presentation_id = MediaRouterBase::CreatePresentationId();
auto callback = base::BindOnce(&MediaRouterMojoImpl::RouteResponseReceived,
weak_factory_.GetWeakPtr(), presentation_id,
incognito, base::Passed(&callbacks), true);
media_route_provider_->ConnectRouteByRouteId(
source_id, route_id, presentation_id, origin, tab_id, timeout, incognito,
std::move(callback));
}
void MediaRouterMojoImpl::TerminateRoute(const MediaRoute::Id& route_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG(2) << "TerminateRoute " << route_id;
auto callback = base::BindOnce(&MediaRouterMojoImpl::OnTerminateRouteResult,
weak_factory_.GetWeakPtr(), route_id);
media_route_provider_->TerminateRoute(route_id, std::move(callback));
}
void MediaRouterMojoImpl::DetachRoute(const MediaRoute::Id& route_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
media_route_provider_->DetachRoute(route_id);
}
void MediaRouterMojoImpl::SendRouteMessage(const MediaRoute::Id& route_id,
const std::string& message,
SendRouteMessageCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
media_route_provider_->SendRouteMessage(route_id, message,
std::move(callback));
}
void MediaRouterMojoImpl::SendRouteBinaryMessage(
const MediaRoute::Id& route_id,
std::unique_ptr<std::vector<uint8_t>> data,
SendRouteMessageCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
media_route_provider_->SendRouteBinaryMessage(route_id, *data,
std::move(callback));
}
void MediaRouterMojoImpl::AddIssue(const IssueInfo& issue_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
issue_manager_.AddIssue(issue_info);
}
void MediaRouterMojoImpl::ClearIssue(const Issue::Id& issue_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
issue_manager_.ClearIssue(issue_id);
}
void MediaRouterMojoImpl::OnUserGesture() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (cast_media_sink_service_)
cast_media_sink_service_->ForceDiscovery();
}
void MediaRouterMojoImpl::SearchSinks(
const MediaSink::Id& sink_id,
const MediaSource::Id& source_id,
const std::string& search_input,
const std::string& domain,
MediaSinkSearchResponseCallback sink_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto sink_search_criteria = mojom::SinkSearchCriteria::New();
sink_search_criteria->input = search_input;
sink_search_criteria->domain = domain;
media_route_provider_->SearchSinks(sink_id, source_id,
std::move(sink_search_criteria),
std::move(sink_callback));
}
scoped_refptr<MediaRouteController> MediaRouterMojoImpl::GetRouteController(
const MediaRoute::Id& route_id) {
auto* route = GetRoute(route_id);
if (!route) {
DVLOG_WITH_INSTANCE(1) << __func__ << ": route not found: " << route_id;
return nullptr;
}
auto it = route_controllers_.find(route_id);
if (it != route_controllers_.end())
return scoped_refptr<MediaRouteController>(it->second);
scoped_refptr<MediaRouteController> route_controller;
switch (route->controller_type()) {
case RouteControllerType::kNone:
DVLOG_WITH_INSTANCE(1)
<< __func__ << ": route does not support controller: " << route_id;
return nullptr;
case RouteControllerType::kGeneric:
route_controller = new MediaRouteController(route_id, context_);
break;
case RouteControllerType::kHangouts:
route_controller = new HangoutsMediaRouteController(route_id, context_);
break;
}
DCHECK(route_controller);
auto callback = base::BindOnce(&MediaRouterMojoImpl::OnMediaControllerCreated,
weak_factory_.GetWeakPtr(), route_id);
media_route_provider_->CreateMediaRouteController(
route_id, route_controller->CreateControllerRequest(),
route_controller->BindObserverPtr(), std::move(callback));
route_controllers_.emplace(route_id, route_controller.get());
return route_controller;
}
void MediaRouterMojoImpl::ProvideSinks(const std::string& provider_name,
std::vector<MediaSinkInternal> sinks) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "Provider [" << provider_name << "] found "
<< sinks.size() << " devices...";
media_route_provider_->ProvideSinks(provider_name, std::move(sinks));
}
bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
MediaSinksObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Create an observer list for the media source and add |observer|
// to it. Fail if |observer| is already registered.
const std::string& source_id = observer->source().id();
std::unique_ptr<MediaSinksQuery>& sinks_query = sinks_queries_[source_id];
bool is_new_query = false;
if (!sinks_query) {
is_new_query = true;
sinks_query = base::MakeUnique<MediaSinksQuery>();
} else {
DCHECK(!sinks_query->observers.HasObserver(observer));
}
// If sink availability is UNAVAILABLE, then there is no need to call MRPM.
// |observer| can be immediately notified with an empty list.
sinks_query->observers.AddObserver(observer);
if (availability_ == mojom::MediaRouter::SinkAvailability::UNAVAILABLE) {
observer->OnSinksUpdated(std::vector<MediaSink>(),
std::vector<url::Origin>());
} else {
// Need to call MRPM to start observing sinks if the query is new.
if (is_new_query) {
media_route_provider_->StartObservingMediaSinks(source_id);
sinks_query->is_active = true;
} else if (sinks_query->cached_sink_list) {
observer->OnSinksUpdated(*sinks_query->cached_sink_list,
sinks_query->origins);
}
}
return true;
}
void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
MediaSinksObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const MediaSource::Id& source_id = observer->source().id();
auto it = sinks_queries_.find(source_id);
if (it == sinks_queries_.end() ||
!it->second->observers.HasObserver(observer)) {
return;
}
// If we are removing the final observer for the source, then stop
// observing sinks for it.
// might_have_observers() is reliable here on the assumption that this call
// is not inside the ObserverList iteration.
it->second->observers.RemoveObserver(observer);
if (!it->second->observers.might_have_observers()) {
// Only ask MRPM to stop observing media sinks if the availability is not
// UNAVAILABLE.
// Otherwise, the MRPM would have discarded the queries already.
if (availability_ !=
mojom::MediaRouter::SinkAvailability::UNAVAILABLE) {
media_route_provider_->StopObservingMediaSinks(source_id);
}
sinks_queries_.erase(source_id);
}
}
void MediaRouterMojoImpl::RegisterMediaRoutesObserver(
MediaRoutesObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const MediaSource::Id source_id = observer->source_id();
auto& routes_query = routes_queries_[source_id];
bool is_new_query = false;
if (!routes_query) {
is_new_query = true;
routes_query = base::MakeUnique<MediaRoutesQuery>();
} else {
DCHECK(!routes_query->observers.HasObserver(observer));
}
routes_query->observers.AddObserver(observer);
if (is_new_query) {
media_route_provider_->StartObservingMediaRoutes(source_id);
// The MRPM will call MediaRouterMojoImpl::OnRoutesUpdated() soon, if there
// are any existing routes the new observer should be aware of.
} else if (routes_query->cached_route_list) {
// Return to the event loop before notifying of a cached route list because
// MediaRoutesObserver is calling this method from its constructor, and that
// must complete before invoking its virtual OnRoutesUpdated() method.
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&MediaRouterMojoImpl::NotifyOfExistingRoutesIfRegistered,
weak_factory_.GetWeakPtr(), source_id, observer));
}
}
void MediaRouterMojoImpl::NotifyOfExistingRoutesIfRegistered(
const MediaSource::Id& source_id,
MediaRoutesObserver* observer) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Check that the route query still exists with a cached result, and that the
// observer is still registered. Otherwise, there is nothing to report to the
// observer.
const auto it = routes_queries_.find(source_id);
if (it == routes_queries_.end() || !it->second->cached_route_list ||
!it->second->observers.HasObserver(observer)) {
return;
}
observer->OnRoutesUpdated(*it->second->cached_route_list,
it->second->joinable_route_ids);
}
void MediaRouterMojoImpl::UnregisterMediaRoutesObserver(
MediaRoutesObserver* observer) {
const MediaSource::Id source_id = observer->source_id();
auto it = routes_queries_.find(source_id);
if (it == routes_queries_.end() ||
!it->second->observers.HasObserver(observer)) {
return;
}
// If we are removing the final observer for the source, then stop
// observing routes for it.
// might_have_observers() is reliable here on the assumption that this call
// is not inside the ObserverList iteration.
it->second->observers.RemoveObserver(observer);
if (!it->second->observers.might_have_observers()) {
media_route_provider_->StopObservingMediaRoutes(source_id);
routes_queries_.erase(source_id);
}
}
void MediaRouterMojoImpl::RegisterIssuesObserver(IssuesObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
issue_manager_.RegisterObserver(observer);
}
void MediaRouterMojoImpl::UnregisterIssuesObserver(IssuesObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
issue_manager_.UnregisterObserver(observer);
}
void MediaRouterMojoImpl::RegisterRouteMessageObserver(
RouteMessageObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(observer);
const MediaRoute::Id& route_id = observer->route_id();
auto& observer_list = message_observers_[route_id];
if (!observer_list) {
observer_list =
base::MakeUnique<base::ObserverList<RouteMessageObserver>>();
} else {
DCHECK(!observer_list->HasObserver(observer));
}
bool should_listen = !observer_list->might_have_observers();
observer_list->AddObserver(observer);
if (should_listen)
media_route_provider_->StartListeningForRouteMessages(route_id);
}
void MediaRouterMojoImpl::UnregisterRouteMessageObserver(
RouteMessageObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(observer);
const MediaRoute::Id& route_id = observer->route_id();
auto it = message_observers_.find(route_id);
if (it == message_observers_.end() || !it->second->HasObserver(observer))
return;
it->second->RemoveObserver(observer);
if (!it->second->might_have_observers()) {
message_observers_.erase(route_id);
media_route_provider_->StopListeningForRouteMessages(route_id);
}
}
void MediaRouterMojoImpl::DetachRouteController(
const MediaRoute::Id& route_id,
MediaRouteController* controller) {
auto it = route_controllers_.find(route_id);
if (it != route_controllers_.end() && it->second == controller)
route_controllers_.erase(it);
}
void MediaRouterMojoImpl::OnRouteMessagesReceived(
const std::string& route_id,
const std::vector<content::PresentationConnectionMessage>& messages) {
DVLOG_WITH_INSTANCE(1) << "OnRouteMessagesReceived";
if (messages.empty())
return;
auto it = message_observers_.find(route_id);
if (it == message_observers_.end())
return;
for (auto& observer : *it->second)
observer.OnMessagesReceived(messages);
}
void MediaRouterMojoImpl::OnSinkAvailabilityUpdated(
SinkAvailability availability) {
if (availability_ == availability)
return;
availability_ = availability;
if (availability_ == mojom::MediaRouter::SinkAvailability::UNAVAILABLE) {
// Sinks are no longer available. MRPM has already removed all sink queries.
for (auto& source_and_query : sinks_queries_) {
const auto& query = source_and_query.second;
query->is_active = false;
query->cached_sink_list = base::nullopt;
query->origins.clear();
}
} else {
// Sinks are now available. Tell MRPM to start all sink queries again.
for (const auto& source_and_query : sinks_queries_) {
media_route_provider_->StartObservingMediaSinks(source_and_query.first);
source_and_query.second->is_active = true;
}
}
}
void MediaRouterMojoImpl::OnPresentationConnectionStateChanged(
const std::string& route_id,
content::PresentationConnectionState state) {
NotifyPresentationConnectionStateChange(route_id, state);
}
void MediaRouterMojoImpl::OnPresentationConnectionClosed(
const std::string& route_id,
content::PresentationConnectionCloseReason reason,
const std::string& message) {
NotifyPresentationConnectionClose(route_id, reason, message);
}
void MediaRouterMojoImpl::OnTerminateRouteResult(
const MediaRoute::Id& route_id,
const base::Optional<std::string>& error_text,
RouteRequestResult::ResultCode result_code) {
if (result_code != RouteRequestResult::OK) {
LOG(WARNING) << "Failed to terminate route " << route_id
<< ": result_code = " << result_code << ", "
<< error_text.value_or(std::string());
}
MediaRouterMojoMetrics::RecordMediaRouteProviderTerminateRoute(result_code);
}
void MediaRouterMojoImpl::SyncStateToMediaRouteProvider() {
DCHECK(media_route_provider_);
// Sink queries.
if (availability_ != mojom::MediaRouter::SinkAvailability::UNAVAILABLE) {
for (const auto& it : sinks_queries_) {
media_route_provider_->StartObservingMediaSinks(it.first);
it.second->is_active = true;
}
}
// Route queries.
for (const auto& it : routes_queries_)
media_route_provider_->StartObservingMediaRoutes(it.first);
// Route messages.
for (const auto& it : message_observers_)
media_route_provider_->StartListeningForRouteMessages(it.first);
StartDiscovery();
}
void MediaRouterMojoImpl::StartDiscovery() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "StartDiscovery";
if (media_router::CastDiscoveryEnabled()) {
if (!cast_media_sink_service_) {
cast_media_sink_service_ = new CastMediaSinkService(
base::Bind(&MediaRouterMojoImpl::ProvideSinks,
weak_factory_.GetWeakPtr(), "cast"),
context_,
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO));
}
cast_media_sink_service_->Start();
}
if (media_router::DialLocalDiscoveryEnabled()) {
if (!dial_media_sink_service_proxy_) {
dial_media_sink_service_proxy_ = new DialMediaSinkServiceProxy(
base::Bind(&MediaRouterMojoImpl::ProvideSinks,
weak_factory_.GetWeakPtr(), "dial"),
context_);
dial_media_sink_service_proxy_->SetObserver(
cast_media_sink_service_.get());
}
dial_media_sink_service_proxy_->Start();
}
}
void MediaRouterMojoImpl::UpdateMediaSinks(
const MediaSource::Id& source_id) {
media_route_provider_->UpdateMediaSinks(source_id);
}
void MediaRouterMojoImpl::RemoveInvalidRouteControllers(
const std::vector<MediaRoute>& routes) {
auto it = route_controllers_.begin();
while (it != route_controllers_.end()) {
if (GetRoute(it->first)) {
++it;
} else {
it->second->Invalidate();
it = route_controllers_.erase(it);
}
}
}
void MediaRouterMojoImpl::OnMediaControllerCreated(
const MediaRoute::Id& route_id,
bool success) {
DVLOG_WITH_INSTANCE(1) << "OnMediaControllerCreated: " << route_id
<< (success ? " was successful." : " failed.");
MediaRouterMojoMetrics::RecordMediaRouteControllerCreationResult(success);
}
void MediaRouterMojoImpl::OnMediaRemoterCreated(
int32_t tab_id,
media::mojom::MirrorServiceRemoterPtr remoter,
media::mojom::MirrorServiceRemotingSourceRequest source_request) {
DVLOG_WITH_INSTANCE(1) << __func__ << ": tab_id = " << tab_id;
auto it = remoting_sources_.find(tab_id);
if (it == remoting_sources_.end()) {
LOG(WARNING) << __func__
<< ": No registered remoting source for tab_id = " << tab_id;
return;
}
CastRemotingConnector* connector = it->second;
connector->ConnectToService(std::move(source_request), std::move(remoter));
}
} // namespace media_router