Commit d2f3bea0 authored by kmarshall's avatar kmarshall Committed by Commit bot

Add media router common classes and unittests.

Create makefiles and integrate MR with GN build.
Add to GYP build.

BUG=460660
R=scherkus@chromium.org,DaleCurtis@chromium.org,xhwang@chromium.org,mfoltz@chromium.org,sky@chromium.org

Review URL: https://codereview.chromium.org/949293004

Cr-Commit-Position: refs/heads/master@{#320186}
parent 3df97b20
......@@ -124,6 +124,13 @@ group("gn_all") {
deps += [ "//ui/ozone" ]
}
if (enable_media_router) {
deps += [
"//chrome/browser/media/router/",
"//chrome/browser/media/router:unit_tests",
]
}
if (is_win || is_mac || is_chromeos) {
# RLZ works on these platforms.
# TODO(GYP): Is this target needed, or pulled in automatically?
......
# 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.
#
import("//testing/test.gni")
source_set("router") {
deps = [
"//base",
"//url",
]
sources = [
"media_route.cc",
"media_route.h",
"media_route_id.h",
"media_sink.cc",
"media_sink.h",
"media_source.cc",
"media_source.h",
"media_source_helper.cc",
"media_source_helper.h",
"route_id_manager.cc",
"route_id_manager.h",
]
}
source_set("unit_tests") {
testonly = true
deps = [
":router",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
]
sources = [
"media_route_unittest.cc",
"media_sink_unittest.cc",
"media_source_unittest.cc",
"route_id_manager_unittest.cc",
]
}
# Optional standalone test binary, for faster isolated builds.
test("unit_tests_main") {
deps = [
":unit_tests",
"//testing/gmock:gmock_main",
]
sources = [
":unittest_files",
]
}
// 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/media_route.h"
#include "base/logging.h"
#include "chrome/browser/media/router/media_source.h"
namespace media_router {
MediaRoute::MediaRoute(const MediaRouteId& media_route_id,
const MediaSource& media_source,
const MediaSink& media_sink,
const std::string& description,
bool is_local)
: media_route_id_(media_route_id),
media_source_(media_source),
media_sink_(media_sink),
description_(description),
is_local_(is_local),
state_(MEDIA_ROUTE_STATE_NEW) {
}
MediaRoute::~MediaRoute() {
}
bool MediaRoute::Equals(const MediaRoute& other) const {
return media_route_id_ == other.media_route_id_;
}
} // namespace media_router
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_H_
#define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_H_
#include <string>
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/media/router/media_route_id.h"
#include "chrome/browser/media/router/media_sink.h"
#include "chrome/browser/media/router/media_source.h"
#include "url/gurl.h"
namespace media_router {
using RouteRequestId = int64;
class MediaRouteFactory;
// For now, a simple transition graph: NEW -> CONNECTED -> CLOSED.
enum MediaRouteState {
// The route is new and not yet connected to a sink.
MEDIA_ROUTE_STATE_NEW,
// The route is active and connected to a sink.
MEDIA_ROUTE_STATE_CONNECTED,
// The route has been disconnected.
MEDIA_ROUTE_STATE_CLOSED
};
// MediaRoute objects contain the status and metadata of a routing
// operation. The fields are immutable and reflect the route status
// only at the time of object creation. Updated route statuses must
// be retrieved as new MediaRoute objects from the Media Router.
class MediaRoute {
public:
// |media_route_id|: ID of the route. New route IDs should be created
// by the RouteIdManager class.
// |media_source|: Description of source of the route.
// |media_sink|: The sink that is receiving the media.
// |description|: Description of the route to be displayed.
// |is_local|: true if the route was created from this browser.
MediaRoute(const MediaRouteId& media_route_id,
const MediaSource& media_source,
const MediaSink& media_sink,
const std::string& description,
bool is_local);
~MediaRoute();
// The media route identifier.
const MediaRouteId& media_route_id() const { return media_route_id_; }
// The state of the media route.
MediaRouteState state() const { return state_; }
// The media source being routed.
const MediaSource& media_source() const { return media_source_; }
// The sink being routed to.
const MediaSink& media_sink() const { return media_sink_; }
// The description of the media route activity, for example
// "Playing Foo Bar Music All Access."
// TODO(kmarshall): Do we need to pass locale for bidi rendering?
const std::string& description() const { return description_; }
// Returns |true| if the route is created locally (versus discovered
// by a media route provider.)
bool is_local() const { return is_local_; }
bool Equals(const MediaRoute& other) const;
private:
const MediaRouteId media_route_id_;
const MediaSource media_source_;
const MediaSink media_sink_;
const std::string description_;
const bool is_local_;
const MediaRouteState state_;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_H_
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_ID_H_
#define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_ID_H_
#include <string>
namespace media_router {
using MediaRouteId = std::string;
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_ID_H_
// 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/media_route.h"
#include "chrome/browser/media/router/media_sink.h"
#include "chrome/browser/media/router/media_source_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media_router {
// Tests the == operator to ensure that only route ID equality is being checked.
TEST(MediaRouteTest, Equals) {
MediaRoute route1("routeId1", ForCastAppMediaSource("DialApp"),
MediaSink("sinkId", "sinkName"),
"Description", false);
// Same as route1 with different sink ID.
MediaRoute route2("routeId1", ForCastAppMediaSource("DialApp"),
MediaSink("differentSinkId", "different sink"),
"Description", false);
EXPECT_TRUE(route1.Equals(route2));
// Same as route1 with different description.
MediaRoute route3("routeId1", ForCastAppMediaSource("DialApp"),
MediaSink("sinkId", "sinkName"),
"differentDescription", false);
EXPECT_TRUE(route1.Equals(route3));
// Same as route1 with different is_local.
MediaRoute route4("routeId1", ForCastAppMediaSource("DialApp"),
MediaSink("sinkId", "sinkName"),
"Description", true);
EXPECT_TRUE(route1.Equals(route4));
// The ID is different from route1's.
MediaRoute route5("routeId2", ForCastAppMediaSource("DialApp"),
MediaSink("sinkId", "sinkName"),
"Description", false);
EXPECT_FALSE(route1.Equals(route5));
}
} // namespace media_router
# 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.
{
'targets': [
{
'target_name': 'media_router',
'type': 'static_library',
'include_dirs': [
'<(DEPTH)',
],
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/url/url.gyp:url_lib',
],
'sources': [
'common.h',
'media_route.cc',
'media_route.h',
'media_route_id.h',
'media_sink.cc',
'media_sink.h',
'media_source.cc',
'media_source.h',
'media_source_helper.cc',
'media_source_helper.h',
'route_id_manager.cc',
'route_id_manager.h',
],
},
],
}
# 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.
{
'sources': [
'media_route_unittest.cc',
'media_sink_unittest.cc',
'media_source_helper_unittest.cc',
'media_source_unittest.cc',
'route_id_manager_unittest.cc',
],
}
// 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/media_sink.h"
namespace media_router {
MediaSink::MediaSink(const MediaSinkId& sink_id,
const std::string& name)
: sink_id_(sink_id), name_(name) {
}
MediaSink::~MediaSink() {
}
bool MediaSink::Equals(const MediaSink& other) const {
return sink_id_ == other.sink_id_;
}
} // namespace media_router
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SINK_H_
#define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SINK_H_
#include <string>
#include "chrome/browser/media/router/media_route_id.h"
namespace media_router {
using MediaSinkId = std::string;
// Represents a sink to which media can be routed.
class MediaSink {
public:
// |sink_id|: Unique identifier for the MediaSink.
// |name|: Descriptive name of the MediaSink.
MediaSink(const MediaSinkId& sink_id,
const std::string& name);
~MediaSink();
const MediaSinkId& sink_id() const { return sink_id_; }
const std::string& name() const { return name_; }
bool Equals(const MediaSink& other) const;
private:
const MediaSinkId sink_id_;
const std::string name_;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SINK_H_
// 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/media_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media_router {
TEST(MediaSinkTest, Equals) {
MediaSink sink1("sinkId", "Sink");
// Same as sink1.
MediaSink sink2("sinkId", "Sink");
EXPECT_TRUE(sink1.Equals(sink2));
// Sink name is different from sink1's.
MediaSink sink3("sinkId", "Other Sink");
EXPECT_TRUE(sink1.Equals(sink3));
// Sink ID is diffrent from sink1's.
MediaSink sink4("otherSinkId", "Sink");
EXPECT_FALSE(sink1.Equals(sink4));
}
} // namespace media_router
// 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/media_source.h"
#include <string>
namespace media_router {
MediaSource::MediaSource(const std::string& source_id)
: id_(source_id) {
}
MediaSource::~MediaSource() {}
std::string MediaSource::id() const {
return id_;
}
} // namespace media_router
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_H_
#define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_H_
#include <string>
namespace media_router {
class MediaSource {
public:
explicit MediaSource(const std::string& id);
~MediaSource();
// Gets the ID of the media source.
std::string id() const;
private:
std::string id_;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_H_
// 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/media_source_helper.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/media/router/media_source.h"
#include "url/gurl.h"
namespace media_router {
// Prefixes used to format and detect various protocols' media source URNs.
// See: https://www.ietf.org/rfc/rfc3406.txt
const char kTabMediaUrnPrefix[] = "urn:x-org.chromium.media:source:tab";
const char kDesktopMediaUrn[] = "urn:x-org.chromium.media:source:desktop";
const char kCastUrnPrefix[] = "urn:x-com.google.cast:application:";
MediaSource ForTabMediaSource(int tab_id) {
return MediaSource(base::StringPrintf("%s:%d", kTabMediaUrnPrefix, tab_id));
}
MediaSource ForDesktopMediaSource() {
return MediaSource(std::string(kDesktopMediaUrn));
}
// TODO(mfoltz): Remove when the TODO in
// MediaSourceManager::GetDefaultMediaSource is resolved.
MediaSource ForCastAppMediaSource(const std::string& app_id) {
return MediaSource(kCastUrnPrefix + app_id);
}
MediaSource ForPresentationUrl(const std::string& presentation_url) {
return MediaSource(presentation_url);
}
bool IsMirroringMediaSource(const MediaSource& source) {
return StartsWithASCII(source.id(), kDesktopMediaUrn, true) ||
StartsWithASCII(source.id(), kTabMediaUrnPrefix, true);
}
bool IsValidMediaSource(const MediaSource& source) {
if (IsMirroringMediaSource(source) ||
StartsWithASCII(source.id(), kCastUrnPrefix, true)) {
return true;
}
GURL url(source.id());
return url.is_valid() && url.SchemeIsHTTPOrHTTPS();
}
} // namespace media_router
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_HELPER_H_
#define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_HELPER_H_
#include <string>
#include "chrome/browser/media/router/media_source.h"
namespace media_router {
// Helper library for protocol-specific media source object creation.
// TODO(kmarshall): Should these creation methods be moved to the WebUI, which
// (excluding Presentation API) is their only caller? The MR base code can be
// Also, consider generating an is_mirroring state boolean at the time of URN
// creation so that the mirroring status does not have to be determined from a
// string prefix check.
// These changes would allow the MR to handle MediaSource objects in the same
// type agnostic fashion vs. having to format and parse URNs and track which
// MediaSource types are mirroring-enabled.
// Returns MediaSource URI depending on the type of source.
MediaSource ForTabMediaSource(int tab_id);
MediaSource ForDesktopMediaSource();
MediaSource ForCastAppMediaSource(const std::string& app_id);
MediaSource ForPresentationUrl(const std::string& presentation_url);
// Returns true if |source| outputs its content via mirroring.
bool IsMirroringMediaSource(const MediaSource& source);
// Checks that |source| is a parseable URN and is of a known type.
// Does not deeper protocol-level syntax checks.
bool IsValidMediaSource(const MediaSource& source);
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_HELPER_H_
// 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/media_source.h"
#include "chrome/browser/media/router/media_source_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media_router {
TEST(MediaSourcesTest, IsMirroringMediaSource) {
EXPECT_TRUE(IsMirroringMediaSource(ForTabMediaSource(123)));
EXPECT_TRUE(IsMirroringMediaSource(ForDesktopMediaSource()));
EXPECT_FALSE(IsMirroringMediaSource(ForCastAppMediaSource("CastApp")));
EXPECT_FALSE(IsMirroringMediaSource(ForPresentationUrl("http://url")));
}
TEST(MediaSourcesTest, CreateMediaSource) {
EXPECT_EQ("urn:x-org.chromium.media:source:tab:123",
ForTabMediaSource(123).id());
EXPECT_EQ("urn:x-org.chromium.media:source:desktop",
ForDesktopMediaSource().id());
EXPECT_EQ("urn:x-com.google.cast:application:DEADBEEF",
ForCastAppMediaSource("DEADBEEF").id());
EXPECT_EQ("http://example.com/",
ForPresentationUrl("http://example.com/").id());
}
TEST(MediaSourcesTest, IsValidMediaSource) {
EXPECT_TRUE(IsValidMediaSource(ForTabMediaSource(123)));
EXPECT_TRUE(IsValidMediaSource(ForDesktopMediaSource()));
EXPECT_TRUE(IsValidMediaSource(ForCastAppMediaSource("DEADBEEF")));
EXPECT_TRUE(IsValidMediaSource(ForPresentationUrl("http://example.com/")));
EXPECT_TRUE(IsValidMediaSource(ForPresentationUrl("https://example.com/")));
// Disallowed scheme
EXPECT_FALSE(
IsValidMediaSource(ForPresentationUrl("file:///some/local/path")));
// Not a URL
EXPECT_FALSE(IsValidMediaSource(ForPresentationUrl("totally not a url")));
}
} // namespace media_router
// 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/media_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media_router {
// Test that the object's getters match the constructor parameters.
TEST(MediaSourceTest, Constructor) {
MediaSource source1("urn:x-com.google.cast:application:DEADBEEF");
EXPECT_EQ("urn:x-com.google.cast:application:DEADBEEF", source1.id());
}
} // namespace media_router
// 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/route_id_manager.h"
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/media/router/media_route.h"
namespace media_router {
const char kLocalRoutePrefix[] = "route-local-";
RouteIDManager::RouteIDManager() : next_local_id_(0) {}
std::string RouteIDManager::ForLocalRoute() {
DCHECK(CalledOnValidThread());
return kLocalRoutePrefix + base::Uint64ToString(next_local_id_++);
}
// static
RouteIDManager* RouteIDManager::GetInstance() {
return Singleton<RouteIDManager>::get();
}
} // namespace media_router
// 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.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
#define CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
#include <string>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/singleton.h"
#include "base/threading/non_thread_safe.h"
namespace media_router {
class MediaRoute;
// Shared singleton which coordinates the assignment of unique IDs to
// MediaRoute objects.
// Class is not threadsafe; IDs should be created on the same thread.
class RouteIDManager : public base::NonThreadSafe {
public:
static RouteIDManager* GetInstance();
std::string ForLocalRoute();
private:
FRIEND_TEST_ALL_PREFIXES(RouteIDManagerTest, ForLocalRoute);
friend struct DefaultSingletonTraits<RouteIDManager>;
RouteIDManager();
// Monotonically increasing ID number.
uint64 next_local_id_;
DISALLOW_COPY_AND_ASSIGN(RouteIDManager);
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_ROUTE_ID_MANAGER_H_
// 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/route_id_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media_router {
TEST(RouteIDManagerTest, ForLocalRoute) {
// Singleton instance is left unused for better test isolation.
RouteIDManager manager1;
EXPECT_EQ("route-local-0", manager1.ForLocalRoute());
EXPECT_EQ("route-local-1", manager1.ForLocalRoute());
RouteIDManager manager2;
EXPECT_EQ("route-local-0", manager2.ForLocalRoute());
}
} // namespace media_router
......@@ -3182,6 +3182,11 @@
['enable_task_manager==1', {
'sources': [ '<@(chrome_browser_task_manager_sources)' ],
}],
['enable_media_router==1', {
'dependencies': [
'browser/media/router/media_router.gyp:media_router',
],
}],
['enable_spellcheck==1', {
'sources': [ '<@(chrome_browser_spellchecker_sources)' ],
'dependencies': [
......
......@@ -2327,6 +2327,11 @@
['enable_print_preview==1', {
'sources': [ '<@(chrome_unit_tests_print_preview_sources)' ],
}],
['enable_media_router==1', {
'includes': [
'browser/media/router/media_router_tests.gypi',
],
}],
['enable_captive_portal_detection==1', {
'sources': [ '<@(chrome_unit_tests_captive_portal_sources)' ],
}],
......
......@@ -1484,6 +1484,9 @@ if (!is_android) {
".",
"//chrome")
}
if (enable_media_router) {
deps += [ "//chrome/browser/media/router:unit_tests" ]
}
if (is_chromeos) {
sources +=
rebase_path(unit_gypi_values.chrome_unit_tests_chromeos_sources,
......
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