Commit 52dda118 authored by Takumi Fujimoto's avatar Takumi Fujimoto Committed by Commit Bot

[Media Router] Better sink availability tracking

- When sink availability changes for an MRP, start/stop observing sinks only for that MRP
- Make WiredDisplayMRP report sink availability updates

Bug: 789277,777650
Change-Id: I3d1a087ca39a4830403d6d2f0f00bf1411388f33
Reviewed-on: https://chromium-review.googlesource.com/794106Reviewed-by: default avatarDerek Cheng <imcheng@chromium.org>
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521550}
parent 09f677bd
......@@ -538,6 +538,14 @@ bool MediaRouterMojoImpl::ProviderSinkAvailability::SetAvailabilityForProvider(
}
}
bool MediaRouterMojoImpl::ProviderSinkAvailability::IsAvailableForProvider(
mojom::MediaRouteProvider::Id provider_id) const {
const auto& it = availabilities_.find(provider_id);
return it == availabilities_.end()
? false
: it->second != SinkAvailability::UNAVAILABLE;
}
bool MediaRouterMojoImpl::ProviderSinkAvailability::IsAvailable() const {
return overall_availability_ != SinkAvailability::UNAVAILABLE;
}
......@@ -578,9 +586,11 @@ bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
// If sink availability is UNAVAILABLE or the query isn't new, then there is
// no need to call MRPs.
if (availability_.IsAvailable() && is_new_query) {
for (const auto& provider : media_route_providers_)
provider.second->StartObservingMediaSinks(source_id);
if (is_new_query) {
for (const auto& provider : media_route_providers_) {
if (sink_availability_.IsAvailableForProvider(provider.first))
provider.second->StartObservingMediaSinks(source_id);
}
}
return true;
}
......@@ -591,9 +601,8 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
const MediaSource::Id& source_id = observer->source().id();
auto it = sinks_queries_.find(source_id);
if (it == sinks_queries_.end() || !it->second->HasObserver(observer)) {
if (it == sinks_queries_.end() || !it->second->HasObserver(observer))
return;
}
// If we are removing the final observer for the source, then stop
// observing sinks for it.
......@@ -603,8 +612,8 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
if (!it->second->HasObservers()) {
// Only ask MRPs to stop observing media sinks if there are sinks available.
// Otherwise, the MRPs would have discarded the queries already.
if (availability_.IsAvailable()) {
for (const auto& provider : media_route_providers_)
for (const auto& provider : media_route_providers_) {
if (sink_availability_.IsAvailableForProvider(provider.first))
provider.second->StopObservingMediaSinks(source_id);
}
sinks_queries_.erase(source_id);
......@@ -753,16 +762,15 @@ void MediaRouterMojoImpl::OnRouteMessagesReceived(
void MediaRouterMojoImpl::OnSinkAvailabilityUpdated(
MediaRouteProviderId provider_id,
SinkAvailability availability) {
if (!availability_.SetAvailabilityForProvider(provider_id, availability))
if (!sink_availability_.SetAvailabilityForProvider(provider_id, availability))
return;
if (availability_.IsAvailable()) {
// Sinks are now available. Tell MRPs to start all sink queries again.
for (const auto& source_and_query : sinks_queries_) {
for (const auto& provider : media_route_providers_)
provider.second->StartObservingMediaSinks(source_and_query.first);
}
} else {
if (availability != SinkAvailability::UNAVAILABLE) {
// Sinks are now available. Tell the MRP to start all sink queries again.
auto& provider = media_route_providers_[provider_id];
for (const auto& source_and_query : sinks_queries_)
provider->StartObservingMediaSinks(source_and_query.first);
} else if (!sink_availability_.IsAvailable()) {
// Sinks are no longer available. MRPs have already removed all sink
// queries.
for (auto& source_and_query : sinks_queries_)
......@@ -807,7 +815,7 @@ void MediaRouterMojoImpl::SyncStateToMediaRouteProvider(
MediaRouteProviderId provider_id) {
const auto& provider = media_route_providers_[provider_id];
// Sink queries.
if (availability_.IsAvailable()) {
if (sink_availability_.IsAvailableForProvider(provider_id)) {
for (const auto& it : sinks_queries_)
provider->StartObservingMediaSinks(it.first);
}
......
......@@ -296,6 +296,10 @@ class MediaRouterMojoImpl : public MediaRouterBase,
bool SetAvailabilityForProvider(MediaRouteProviderId provider_id,
SinkAvailability availability);
// Returns true if the availability for the provider is not UNAVAILABLE.
bool IsAvailableForProvider(
mojom::MediaRouteProvider::Id provider_id) const;
// Returns true if there is a provider whose sink availability isn't
// UNAVAILABLE.
bool IsAvailable() const;
......@@ -407,7 +411,7 @@ class MediaRouterMojoImpl : public MediaRouterBase,
std::string instance_id_;
// The last reported sink availability from the media route providers.
ProviderSinkAvailability availability_;
ProviderSinkAvailability sink_availability_;
// Bindings for Mojo pointers to |this| held by media route providers.
mojo::BindingSet<mojom::MediaRouter> bindings_;
......
......@@ -68,6 +68,7 @@ WiredDisplayMediaRouteProvider::WiredDisplayMediaRouteProvider(
: binding_(this, std::move(request)),
media_router_(std::move(media_router)) {
display::Screen::GetScreen()->AddObserver(this);
ReportSinkAvailability(GetSinks());
}
WiredDisplayMediaRouteProvider::~WiredDisplayMediaRouteProvider() {
......@@ -264,6 +265,7 @@ void WiredDisplayMediaRouteProvider::NotifyRouteObservers() const {
void WiredDisplayMediaRouteProvider::NotifySinkObservers() {
std::vector<MediaSinkInternal> sinks = GetSinks();
device_count_metrics_.RecordDeviceCountsIfNeeded(sinks.size(), sinks.size());
ReportSinkAvailability(sinks);
for (const auto& sink_query : sink_queries_)
media_router_->OnSinksReceived(kProviderId, sink_query, sinks, {});
}
......@@ -290,4 +292,12 @@ std::vector<Display> WiredDisplayMediaRouteProvider::GetAvailableDisplays()
return displays;
}
void WiredDisplayMediaRouteProvider::ReportSinkAvailability(
const std::vector<MediaSinkInternal>& sinks) {
mojom::MediaRouter::SinkAvailability sink_availability =
sinks.empty() ? mojom::MediaRouter::SinkAvailability::UNAVAILABLE
: mojom::MediaRouter::SinkAvailability::PER_SOURCE;
media_router_->OnSinkAvailabilityUpdated(kProviderId, sink_availability);
}
} // namespace media_router
......@@ -106,6 +106,9 @@ class WiredDisplayMediaRouteProvider : public mojom::MediaRouteProvider,
// Sends the current list of sinks to each query in |sink_queries_|.
void NotifySinkObservers();
// Notifies |media_router_| of the current sink availability.
void ReportSinkAvailability(const std::vector<MediaSinkInternal>& sinks);
// Returns a list of available sinks. A display can be a sink if it is
// secondary and does not mirror a primary display.
std::vector<MediaSinkInternal> GetSinks() const;
......
......@@ -157,6 +157,41 @@ TEST_F(WiredDisplayMediaRouteProviderTest, GetDisplaysAsSinks) {
base::RunLoop().RunUntilIdle();
}
TEST_F(WiredDisplayMediaRouteProviderTest, NotifyOnDisplayChange) {
const std::string sink_id1 = GetSinkId(sink_display1_);
provider_pointer_->StartObservingMediaSinks(kPresentationSource);
base::RunLoop().RunUntilIdle();
// Add an external display. MediaRouter should be notified of the sink and the
// sink availability change.
provider_->set_all_displays({primary_display_, sink_display1_});
EXPECT_CALL(router_, OnSinkAvailabilityUpdated(
mojom::MediaRouteProvider::Id::WIRED_DISPLAY,
mojom::MediaRouter::SinkAvailability::PER_SOURCE));
EXPECT_CALL(
router_,
OnSinksReceived(mojom::MediaRouteProvider::Id::WIRED_DISPLAY, _, _, _))
.WillOnce(WithArg<2>(
Invoke([&sink_id1](const std::vector<MediaSinkInternal>& sinks) {
EXPECT_EQ(sinks.size(), 1u);
EXPECT_EQ(sinks[0].sink().id(), sink_id1);
})));
provider_->OnDisplayAdded(sink_display1_);
base::RunLoop().RunUntilIdle();
// Remove the external display. MediaRouter should be notified of the lack of
// sinks.
provider_->set_all_displays({primary_display_});
EXPECT_CALL(router_, OnSinkAvailabilityUpdated(
mojom::MediaRouteProvider::Id::WIRED_DISPLAY,
mojom::MediaRouter::SinkAvailability::UNAVAILABLE));
EXPECT_CALL(router_,
OnSinksReceived(mojom::MediaRouteProvider::Id::WIRED_DISPLAY, _,
IsEmpty(), _));
provider_->OnDisplayRemoved(sink_display1_);
base::RunLoop().RunUntilIdle();
}
TEST_F(WiredDisplayMediaRouteProviderTest, NoSinksForNonPresentationSource) {
EXPECT_CALL(router_,
OnSinksReceived(kProviderId, kNonPresentationSource, _, _))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment