Commit 89346464 authored by Jordan Bayles's avatar Jordan Bayles Committed by Commit Bot

Media Router: Simplify app availability

This patch fixes some issues with tab sink availability by modifying the
MediaRouterMojoImpl to have a single SinksQuery for all tabs,
tabs_sinks_query_, instead of registering a unique sinks query for each
unique tab media source id.

In places where a media source id is expected, specifically for the
media router providers themselves, a hardcoded media source id for tab 0
is passed.

Bug: 1013769, b/154115531
Change-Id: I8cdb05fba9aa813153e66bf3af8e5f3d17581903
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2200015
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Reviewed-by: default avatarTakumi Fujimoto <takumif@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771963}
parent d99c3910
...@@ -205,7 +205,7 @@ void MediaRouterMojoImpl::OnSinksReceived( ...@@ -205,7 +205,7 @@ void MediaRouterMojoImpl::OnSinksReceived(
const std::vector<url::Origin>& origins) { const std::vector<url::Origin>& origins) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DVLOG_WITH_INSTANCE(1) << "OnSinksReceived"; DVLOG_WITH_INSTANCE(1) << "OnSinksReceived";
auto it = sinks_queries_.find(media_source); auto it = sinks_queries_.find(MediaSinksQuery::GetKey(media_source).id());
if (it == sinks_queries_.end()) { if (it == sinks_queries_.end()) {
DVLOG_WITH_INSTANCE(1) << "Received sink list without MediaSinksQuery."; DVLOG_WITH_INSTANCE(1) << "Received sink list without MediaSinksQuery.";
return; return;
...@@ -486,6 +486,25 @@ void MediaRouterMojoImpl::GetMediaController( ...@@ -486,6 +486,25 @@ void MediaRouterMojoImpl::GetMediaController(
std::move(callback)); std::move(callback));
} }
// static
MediaSource MediaRouterMojoImpl::MediaSinksQuery::GetKey(
const MediaSource::Id& id) {
MediaSource source(id);
if (source.IsTabMirroringSource()) {
return MediaSource::ForAnyTab();
}
return source;
}
// static
MediaSource MediaRouterMojoImpl::MediaSinksQuery::GetKey(
const MediaSinksObserver& observer) {
if (!observer.source()) {
return MediaSource{""};
}
return GetKey(observer.source()->id());
}
void MediaRouterMojoImpl::MediaSinksQuery::SetSinksForProvider( void MediaRouterMojoImpl::MediaSinksQuery::SetSinksForProvider(
MediaRouteProviderId provider_id, MediaRouteProviderId provider_id,
const std::vector<MediaSink>& sinks) { const std::vector<MediaSink>& sinks) {
...@@ -652,12 +671,11 @@ void MediaRouterMojoImpl::ProviderSinkAvailability:: ...@@ -652,12 +671,11 @@ void MediaRouterMojoImpl::ProviderSinkAvailability::
bool MediaRouterMojoImpl::RegisterMediaSinksObserver( bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
MediaSinksObserver* observer) { MediaSinksObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Create an observer list for the media source and add |observer| // Create an observer list for the media source and add |observer|
// to it. Fail if |observer| is already registered. // to it. Fail if |observer| is already registered.
const std::string& source_id =
observer->source() ? observer->source()->id() : ""; const MediaSource source = MediaSinksQuery::GetKey(*observer);
std::unique_ptr<MediaSinksQuery>& sinks_query = sinks_queries_[source_id]; std::unique_ptr<MediaSinksQuery>& sinks_query = sinks_queries_[source.id()];
bool is_new_query = false; bool is_new_query = false;
if (!sinks_query) { if (!sinks_query) {
is_new_query = true; is_new_query = true;
...@@ -672,7 +690,7 @@ bool MediaRouterMojoImpl::RegisterMediaSinksObserver( ...@@ -672,7 +690,7 @@ bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
if (is_new_query) { if (is_new_query) {
for (const auto& provider : media_route_providers_) { for (const auto& provider : media_route_providers_) {
if (sink_availability_.IsAvailableForProvider(provider.first)) { if (sink_availability_.IsAvailableForProvider(provider.first)) {
provider.second->StartObservingMediaSinks(source_id); provider.second->StartObservingMediaSinks(source.id());
} }
} }
} }
...@@ -683,9 +701,8 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver( ...@@ -683,9 +701,8 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
MediaSinksObserver* observer) { MediaSinksObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const std::string& source_id = const MediaSource source = MediaSinksQuery::GetKey(*observer);
observer->source() ? observer->source()->id() : ""; auto it = sinks_queries_.find(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; return;
...@@ -694,15 +711,17 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver( ...@@ -694,15 +711,17 @@ void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
// HasObservers() is reliable here on the assumption that this call // HasObservers() is reliable here on the assumption that this call
// is not inside the ObserverList iteration. // is not inside the ObserverList iteration.
it->second->RemoveObserver(observer); it->second->RemoveObserver(observer);
if (!it->second->HasObservers()) { // Since all tabs share the tab sinks query, we don't want to delete it
// here.
if (!it->second->HasObservers() && !source.IsTabMirroringSource()) {
// Only ask MRPs to stop observing media sinks if there are sinks available. // Only ask MRPs to stop observing media sinks if there are sinks available.
// Otherwise, the MRPs would have discarded the queries already. // Otherwise, the MRPs would have discarded the queries already.
for (const auto& provider : media_route_providers_) { for (const auto& provider : media_route_providers_) {
if (sink_availability_.IsAvailableForProvider(provider.first)) { if (sink_availability_.IsAvailableForProvider(provider.first)) {
provider.second->StopObservingMediaSinks(source_id); provider.second->StopObservingMediaSinks(source.id());
} }
} }
sinks_queries_.erase(source_id); sinks_queries_.erase(source.id());
} }
} }
......
...@@ -150,43 +150,14 @@ class MediaRouterMojoImpl : public MediaRouterBase, public mojom::MediaRouter { ...@@ -150,43 +150,14 @@ class MediaRouterMojoImpl : public MediaRouterBase, public mojom::MediaRouter {
friend class MediaRouterFactory; friend class MediaRouterFactory;
friend class MediaRouterMojoImplTest; friend class MediaRouterMojoImplTest;
friend class MediaRouterMojoTest; friend class MediaRouterMojoTest;
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, JoinRoute);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, JoinRouteTimedOutFails); FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, JoinRouteTimedOutFails);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
JoinRouteIncognitoMismatchFails); JoinRouteIncognitoMismatchFails);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
IncognitoRoutesTerminatedOnProfileShutdown);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RegisterAndUnregisterMediaSinksObserver);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RegisterMediaSinksObserverWithAvailabilityChange);
FRIEND_TEST_ALL_PREFIXES(
MediaRouterMojoImplTest,
RegisterAndUnregisterMediaSinksObserverWithAvailabilityChange);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RegisterAndUnregisterMediaRoutesObserver);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RouteMessagesSingleObserver);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RouteMessagesMultipleObservers);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, HandleIssue); FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, HandleIssue);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, GetMediaController);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
FailToCreateRouteController);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
RegisterMediaRoutesObserver_DedupingWithCache);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
PresentationConnectionStateChangedCallback); PresentationConnectionStateChangedCallback);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
PresentationConnectionStateChangedCallbackRemoved); PresentationConnectionStateChangedCallbackRemoved);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
SendSinkRequestsToMultipleProviders);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
SendRouteRequestsToMultipleProviders);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
ObserveSinksFromMultipleProviders);
FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
ObserveRoutesFromMultipleProviders);
FRIEND_TEST_ALL_PREFIXES(MediaRouterDesktopTest, FRIEND_TEST_ALL_PREFIXES(MediaRouterDesktopTest,
SyncStateToMediaRouteProvider); SyncStateToMediaRouteProvider);
FRIEND_TEST_ALL_PREFIXES(ExtensionMediaRouteProviderProxyTest, FRIEND_TEST_ALL_PREFIXES(ExtensionMediaRouteProviderProxyTest,
...@@ -199,6 +170,9 @@ class MediaRouterMojoImpl : public MediaRouterBase, public mojom::MediaRouter { ...@@ -199,6 +170,9 @@ class MediaRouterMojoImpl : public MediaRouterBase, public mojom::MediaRouter {
MediaSinksQuery(); MediaSinksQuery();
~MediaSinksQuery(); ~MediaSinksQuery();
static MediaSource GetKey(const MediaSource::Id& source_id);
static MediaSource GetKey(const MediaSinksObserver& observer);
// Caches the list of sinks for the provider returned from the query. // Caches the list of sinks for the provider returned from the query.
void SetSinksForProvider(MediaRouteProviderId provider_id, void SetSinksForProvider(MediaRouteProviderId provider_id,
const std::vector<MediaSink>& sinks); const std::vector<MediaSink>& sinks);
......
...@@ -21,6 +21,7 @@ namespace { ...@@ -21,6 +21,7 @@ namespace {
// Prefixes used to format and detect various protocols' media source URNs. // Prefixes used to format and detect various protocols' media source URNs.
// See: https://www.ietf.org/rfc/rfc3406.txt // See: https://www.ietf.org/rfc/rfc3406.txt
constexpr char kAnyTabMediaUrn[] = "urn:x-org.chromium.media:source:tab:*";
constexpr char kTabMediaUrnFormat[] = "urn:x-org.chromium.media:source:tab:%d"; constexpr char kTabMediaUrnFormat[] = "urn:x-org.chromium.media:source:tab:%d";
constexpr base::StringPiece kDesktopMediaUrnPrefix = constexpr base::StringPiece kDesktopMediaUrnPrefix =
"urn:x-org.chromium.media:source:desktop:"; "urn:x-org.chromium.media:source:desktop:";
...@@ -67,6 +68,11 @@ MediaSource::MediaSource(const GURL& presentation_url) ...@@ -67,6 +68,11 @@ MediaSource::MediaSource(const GURL& presentation_url)
MediaSource::~MediaSource() = default; MediaSource::~MediaSource() = default;
// static
MediaSource MediaSource::ForAnyTab() {
return MediaSource(std::string(kAnyTabMediaUrn));
}
// static // static
MediaSource MediaSource::ForTab(int tab_id) { MediaSource MediaSource::ForTab(int tab_id) {
return MediaSource(base::StringPrintf(kTabMediaUrnFormat, tab_id)); return MediaSource(base::StringPrintf(kTabMediaUrnFormat, tab_id));
...@@ -87,18 +93,19 @@ MediaSource MediaSource::ForPresentationUrl(const GURL& presentation_url) { ...@@ -87,18 +93,19 @@ MediaSource MediaSource::ForPresentationUrl(const GURL& presentation_url) {
return MediaSource(presentation_url); return MediaSource(presentation_url);
} }
bool MediaSource::IsTabMirroringSource() const {
int tab_id;
return id() == kAnyTabMediaUrn ||
(std::sscanf(id().c_str(), kTabMediaUrnFormat, &tab_id) == 1 &&
tab_id > 0);
}
bool MediaSource::IsDesktopMirroringSource() const { bool MediaSource::IsDesktopMirroringSource() const {
return id() == kUnknownDesktopMediaUrn || return id() == kUnknownDesktopMediaUrn ||
base::StartsWith(id(), kDesktopMediaUrnPrefix, base::StartsWith(id(), kDesktopMediaUrnPrefix,
base::CompareCase::SENSITIVE); base::CompareCase::SENSITIVE);
} }
bool MediaSource::IsTabMirroringSource() const {
int tab_id;
return std::sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id) == 1 &&
tab_id > 0;
}
bool MediaSource::IsMirroringSource() const { bool MediaSource::IsMirroringSource() const {
return IsDesktopMirroringSource() || IsTabMirroringSource(); return IsDesktopMirroringSource() || IsTabMirroringSource();
} }
...@@ -125,7 +132,7 @@ base::Optional<std::string> MediaSource::DesktopStreamId() const { ...@@ -125,7 +132,7 @@ base::Optional<std::string> MediaSource::DesktopStreamId() const {
} }
bool MediaSource::IsValid() const { bool MediaSource::IsValid() const {
return TabId() > 0 || IsDesktopMirroringSource() || return IsTabMirroringSource() || IsDesktopMirroringSource() ||
IsValidPresentationUrl(GURL(id_)); IsValidPresentationUrl(GURL(id_));
} }
......
...@@ -90,6 +90,7 @@ class MediaSource { ...@@ -90,6 +90,7 @@ class MediaSource {
// Protocol-specific media source object creation. // Protocol-specific media source object creation.
// Returns MediaSource URI depending on the type of source. // Returns MediaSource URI depending on the type of source.
static MediaSource ForAnyTab();
static MediaSource ForTab(int tab_id); static MediaSource ForTab(int tab_id);
static MediaSource ForPresentationUrl(const GURL& presentation_url); static MediaSource ForPresentationUrl(const GURL& presentation_url);
...@@ -107,9 +108,8 @@ class MediaSource { ...@@ -107,9 +108,8 @@ class MediaSource {
// extension-based Cast MRP is removed. // extension-based Cast MRP is removed.
static MediaSource ForDesktop(); static MediaSource ForDesktop();
// Returns true if source outputs its content via mirroring.
bool IsDesktopMirroringSource() const;
bool IsTabMirroringSource() const; bool IsTabMirroringSource() const;
bool IsDesktopMirroringSource() const;
bool IsMirroringSource() const; bool IsMirroringSource() const;
// Returns true if this is represents a Cast Presentation URL. // Returns true if this is represents a Cast Presentation URL.
......
...@@ -54,6 +54,18 @@ TEST(MediaSourceTest, ConstructorWithURLString) { ...@@ -54,6 +54,18 @@ TEST(MediaSourceTest, ConstructorWithURLString) {
EXPECT_EQ(test_url, source1.url()); EXPECT_EQ(test_url, source1.url());
} }
TEST(MediaSourceTest, ForAnyTab) {
auto source = MediaSource::ForAnyTab();
EXPECT_EQ("urn:x-org.chromium.media:source:tab:*", source.id());
EXPECT_EQ(-1, source.TabId());
EXPECT_TRUE(source.IsValid());
EXPECT_FALSE(source.IsDesktopMirroringSource());
EXPECT_TRUE(source.IsTabMirroringSource());
EXPECT_TRUE(source.IsMirroringSource());
EXPECT_FALSE(source.IsCastPresentationUrl());
EXPECT_FALSE(source.IsDialSource());
}
TEST(MediaSourceTest, ForTab) { TEST(MediaSourceTest, ForTab) {
auto source = MediaSource::ForTab(123); auto source = MediaSource::ForTab(123);
EXPECT_EQ("urn:x-org.chromium.media:source:tab:123", source.id()); EXPECT_EQ("urn:x-org.chromium.media:source:tab:123", source.id());
......
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