Commit 30c5dfb1 authored by John Williams's avatar John Williams Committed by Commit Bot

[Cast MRP] Support for DefaultActionPolicy + refactoring related code.

Change-Id: I6dd462281b83f0935b8e6af3a9b9a8d2605d5e44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1554249
Commit-Queue: John Williams <jrw@chromium.org>
Reviewed-by: default avatarTakumi Fujimoto <takumif@chromium.org>
Cr-Commit-Position: refs/heads/master@{#650630}
parent 0ffe824e
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#include "chrome/common/media_router/providers/cast/cast_media_source.h" #include "chrome/common/media_router/providers/cast/cast_media_source.h"
#include <utility>
#include "base/containers/flat_map.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/common/media_router/media_source_helper.h" #include "chrome/common/media_router/media_source_helper.h"
...@@ -14,38 +18,107 @@ ...@@ -14,38 +18,107 @@
#include "url/url_util.h" #include "url/url_util.h"
using cast_channel::BroadcastRequest; using cast_channel::BroadcastRequest;
using cast_channel::CastDeviceCapability;
namespace cast_util { namespace cast_util {
using media_router::AutoJoinPolicy;
using media_router::DefaultActionPolicy;
template <> template <>
const EnumTable<media_router::AutoJoinPolicy> const EnumTable<AutoJoinPolicy> EnumTable<AutoJoinPolicy>::instance({
EnumTable<media_router::AutoJoinPolicy>::instance({ {AutoJoinPolicy::kPageScoped, "page_scoped"},
{media_router::AutoJoinPolicy::kTabAndOriginScoped, {AutoJoinPolicy::kTabAndOriginScoped, "tab_and_origin_scoped"},
"tab_and_origin_scoped"}, {AutoJoinPolicy::kOriginScoped, "origin_scoped"},
{media_router::AutoJoinPolicy::kOriginScoped, "origin_scoped"}, });
{media_router::AutoJoinPolicy::kPageScoped, "page_scoped"},
// kNone deliberately omitted. template <>
}); const EnumTable<DefaultActionPolicy> EnumTable<DefaultActionPolicy>::instance({
{DefaultActionPolicy::kCreateSession, "create_session"},
{DefaultActionPolicy::kCastThisTab, "cast_this_tab"},
});
template <>
const EnumTable<CastDeviceCapability> EnumTable<CastDeviceCapability>::instance(
{
{CastDeviceCapability::MULTIZONE_GROUP, "multizone_group"},
{CastDeviceCapability::DEV_MODE, "dev_mode"},
{CastDeviceCapability::AUDIO_IN, "audio_in"},
{CastDeviceCapability::AUDIO_OUT, "audio_out"},
{CastDeviceCapability::VIDEO_IN, "video_in"},
{CastDeviceCapability::VIDEO_OUT, "video_out"},
// NONE deliberately omitted
},
UnsortedEnumTable);
} // namespace cast_util } // namespace cast_util
namespace media_router { namespace media_router {
namespace { namespace {
// Parameter keys used by new Cast URLs. // A nonmember version of base::Optional::value_or that works on pointers as
constexpr char kCapabilitiesKey[] = "capabilities"; // well as instance of base::Optional.
constexpr char kBroadcastNamespaceKey[] = "broadcastNamespace"; template <typename T>
constexpr char kBroadcastMessageKey[] = "broadcastMessage"; inline auto value_or(const T& optional,
constexpr char kClientIdKey[] = "clientId"; const std::decay_t<decltype(*optional)>& default_value)
constexpr char kLaunchTimeoutKey[] = "launchTimeout"; -> std::decay_t<decltype(*optional)> {
constexpr char kAutoJoinPolicyKey[] = "autoJoinPolicy"; return optional ? *optional : default_value;
}
// Parameter keys used by legacy Cast URLs.
constexpr char kLegacyAppIdKey[] = "__castAppId__"; // FindValue() looks up the value associated with a key |key| in a map-like
constexpr char kLegacyBroadcastNamespaceKey[] = "__castBroadcastNamespace__"; // object |map| and returns a pointer to the value if |key| is found, or nullptr
constexpr char kLegacyBroadcastMessageKey[] = "__castBroadcastMessage__"; // otherwise.
constexpr char kLegacyClientIdKey[] = "__castClientId__"; //
constexpr char kLegacyLaunchTimeoutKey[] = "__castLaunchTimeout__"; // The type of |map| can be anything that supports a find() method like
constexpr char kLegacyAutoJoinPolicyKey[] = "__castAutoJoinPolicy__"; // std::map::find, or any iterable object whose values are key/value pairs.
//
// See also FindValueOr().
// Overload for types with a find() method.
template <typename Map, typename = typename Map::key_type>
inline const typename Map::mapped_type* FindValue(
const Map& map,
const typename Map::key_type& key) {
auto it = map.find(key);
if (it == map.end())
return nullptr;
return &it->second;
}
// Overload for types without a find() method.
template <typename Map, typename Key>
auto FindValue(const Map& map, const Key& key) -> const
decltype(begin(map)->second)* {
for (const auto& item : map) {
if (item.first == key)
return &item.second;
}
return nullptr;
}
// Looks up the value associated with a key |key| in a map-like object |map| and
// returns a reference to the value if |key| is found, or |default_value|
// otherwise.
//
// The type of |map| can be anything that supports a find() method like
// std::map::find, or any iterable object whose values are key/value pairs.
template <typename Map, typename Key, typename T>
inline auto FindValueOr(const Map& map, const Key& key, const T& default_value)
-> std::decay_t<decltype(*FindValue(map, key))> {
return value_or(FindValue(map, key), default_value);
}
// Creates a map from the query parameters of |url|. If |url| contains multiple
// values for the same parameter, the last value is used.
base::flat_map<std::string, std::string> MakeQueryMap(const GURL& url) {
base::flat_map<std::string, std::string> result;
for (net::QueryIterator query_it(url); !query_it.IsAtEnd();
query_it.Advance()) {
result[query_it.GetKey()] = query_it.GetValue();
}
return result;
}
// TODO(imcheng): Move to common utils? // TODO(imcheng): Move to common utils?
std::string DecodeURLComponent(const std::string& encoded) { std::string DecodeURLComponent(const std::string& encoded) {
...@@ -60,20 +133,22 @@ std::string DecodeURLComponent(const std::string& encoded) { ...@@ -60,20 +133,22 @@ std::string DecodeURLComponent(const std::string& encoded) {
return std::string(); return std::string();
} }
cast_channel::CastDeviceCapability CastDeviceCapabilityFromString( // Converts a string containing a comma-separated list of capabilities into a
// bitwise OR of CastDeviceCapability values.
BitwiseOr<CastDeviceCapability> CastDeviceCapabilitiesFromString(
const base::StringPiece& s) { const base::StringPiece& s) {
if (s == "video_out") BitwiseOr<CastDeviceCapability> result{};
return cast_channel::CastDeviceCapability::VIDEO_OUT; for (const auto& capability_str : base::SplitStringPiece(
if (s == "video_in") s, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
return cast_channel::CastDeviceCapability::VIDEO_IN; const auto capability =
if (s == "audio_out") cast_util::StringToEnum<CastDeviceCapability>(capability_str);
return cast_channel::CastDeviceCapability::AUDIO_OUT; if (capability) {
if (s == "audio_in") result.Add(*capability);
return cast_channel::CastDeviceCapability::AUDIO_IN; } else {
if (s == "multizone_group") DLOG(ERROR) << "Unkown capability name: " << capability_str;
return cast_channel::CastDeviceCapability::MULTIZONE_GROUP; }
}
return cast_channel::CastDeviceCapability::NONE; return result;
} }
std::unique_ptr<CastMediaSource> CastMediaSourceForTabMirroring( std::unique_ptr<CastMediaSource> CastMediaSourceForTabMirroring(
...@@ -92,28 +167,38 @@ std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring( ...@@ -92,28 +167,38 @@ std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring(
source_id, std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId)})); source_id, std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId)}));
} }
// The logic shared by ParseCastUrl() and ParseLegacyCastUrl().
std::unique_ptr<CastMediaSource> CreateFromURLParams( std::unique_ptr<CastMediaSource> CreateFromURLParams(
const MediaSource::Id& source_id, const MediaSource::Id& source_id,
const std::vector<CastAppInfo>& app_infos, const std::vector<CastAppInfo>& app_infos,
const std::string& auto_join_policy_str, const std::string& auto_join_policy_str,
const std::string& default_action_policy_str,
const std::string& client_id, const std::string& client_id,
const std::string& broadcast_namespace, const std::string& broadcast_namespace,
const std::string& broadcast_message, const std::string& encoded_broadcast_message,
base::TimeDelta launch_timeout) { const std::string& launch_timeout_str) {
if (app_infos.empty()) if (app_infos.empty())
return nullptr; return nullptr;
auto cast_source = std::make_unique<CastMediaSource>( auto cast_source = std::make_unique<CastMediaSource>(
source_id, app_infos, source_id, app_infos,
cast_util::StringToEnum<AutoJoinPolicy>(auto_join_policy_str) cast_util::StringToEnum<AutoJoinPolicy>(auto_join_policy_str)
.value_or(AutoJoinPolicy::kNone)); .value_or(AutoJoinPolicy::kPageScoped),
cast_util::StringToEnum<DefaultActionPolicy>(default_action_policy_str)
.value_or(DefaultActionPolicy::kCreateSession));
cast_source->set_client_id(client_id); cast_source->set_client_id(client_id);
if (!broadcast_namespace.empty() && !broadcast_message.empty()) { if (!broadcast_namespace.empty() && !encoded_broadcast_message.empty()) {
cast_source->set_broadcast_request( cast_source->set_broadcast_request(BroadcastRequest(
BroadcastRequest(broadcast_namespace, broadcast_message)); broadcast_namespace, DecodeURLComponent(encoded_broadcast_message)));
}
int launch_timeout_millis;
if (base::StringToInt(launch_timeout_str, &launch_timeout_millis) &&
launch_timeout_millis > 0) {
cast_source->set_launch_timeout(
base::TimeDelta::FromMilliseconds(launch_timeout_millis));
} }
if (launch_timeout > base::TimeDelta())
cast_source->set_launch_timeout(launch_timeout);
return cast_source; return cast_source;
} }
...@@ -124,78 +209,30 @@ std::unique_ptr<CastMediaSource> ParseCastUrl(const MediaSource::Id& source_id, ...@@ -124,78 +209,30 @@ std::unique_ptr<CastMediaSource> ParseCastUrl(const MediaSource::Id& source_id,
if (app_id.empty()) if (app_id.empty())
return nullptr; return nullptr;
std::string broadcast_namespace, broadcast_message, capabilities; auto params{MakeQueryMap(url)};
std::string client_id, auto_join_policy;
int launch_timeout_millis = 0;
for (net::QueryIterator query_it(url); !query_it.IsAtEnd();
query_it.Advance()) {
std::string key = query_it.GetKey();
std::string value = query_it.GetValue();
if (key.empty() || value.empty())
continue;
if (key == kBroadcastNamespaceKey) {
broadcast_namespace = value;
} else if (key == kBroadcastMessageKey) {
// The broadcast message is URL-encoded.
broadcast_message = DecodeURLComponent(value);
} else if (key == kCapabilitiesKey) {
capabilities = value;
} else if (key == kClientIdKey) {
client_id = value;
} else if (key == kLaunchTimeoutKey) {
if (!base::StringToInt(value, &launch_timeout_millis) ||
launch_timeout_millis < 0)
launch_timeout_millis = 0;
} else if (key == kAutoJoinPolicyKey) {
auto_join_policy = value;
}
}
CastAppInfo app_info(app_id);
if (!capabilities.empty()) {
for (const auto& capability :
base::SplitStringPiece(capabilities, ",", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
app_info.required_capabilities |=
CastDeviceCapabilityFromString(capability);
}
}
return CreateFromURLParams( return CreateFromURLParams(
source_id, {app_info}, auto_join_policy, client_id, broadcast_namespace, source_id,
broadcast_message, {CastAppInfo(app_id, CastDeviceCapabilitiesFromString(
base::TimeDelta::FromMilliseconds(launch_timeout_millis)); FindValueOr(params, "capabilities", "")))},
FindValueOr(params, "autoJoinPolicy", ""),
FindValueOr(params, "defaultActionPolicy", ""),
FindValueOr(params, "clientId", ""),
FindValueOr(params, "broadcastNamespace", ""),
FindValueOr(params, "broadcastMessage", ""),
FindValueOr(params, "launchTimeout", ""));
} }
std::unique_ptr<CastMediaSource> ParseLegacyCastUrl( std::unique_ptr<CastMediaSource> ParseLegacyCastUrl(
const MediaSource::Id& source_id, const MediaSource::Id& source_id,
const GURL& url) { const GURL& url) {
base::StringPairs parameters; base::StringPairs params;
base::SplitStringIntoKeyValuePairs(url.ref(), '=', '/', &parameters); base::SplitStringIntoKeyValuePairs(url.ref(), '=', '/', &params);
// Legacy URLs can specify multiple apps. // Legacy URLs can specify multiple apps.
std::vector<std::string> app_id_params; std::vector<std::string> app_id_params;
std::string broadcast_namespace, broadcast_message; for (const auto& param : params) {
std::string client_id, auto_join_policy; if (param.first == "__castAppId__")
int launch_timeout_millis = 0; app_id_params.push_back(param.second);
for (const auto& key_value : parameters) {
const auto& key = key_value.first;
const auto& value = key_value.second;
if (key == kLegacyAppIdKey) {
app_id_params.push_back(value);
} else if (key == kLegacyBroadcastNamespaceKey) {
broadcast_namespace = value;
} else if (key == kLegacyBroadcastMessageKey) {
// The broadcast message is URL-encoded.
broadcast_message = DecodeURLComponent(value);
} else if (key == kLegacyClientIdKey) {
client_id = value;
} else if (key == kLegacyLaunchTimeoutKey) {
if (!base::StringToInt(value, &launch_timeout_millis) ||
launch_timeout_millis < 0)
launch_timeout_millis = 0;
} else if (key == kLegacyAutoJoinPolicyKey) {
auto_join_policy = value;
}
} }
std::vector<CastAppInfo> app_infos; std::vector<CastAppInfo> app_infos;
...@@ -217,13 +254,8 @@ std::unique_ptr<CastMediaSource> ParseLegacyCastUrl( ...@@ -217,13 +254,8 @@ std::unique_ptr<CastMediaSource> ParseLegacyCastUrl(
if (app_id.empty()) if (app_id.empty())
continue; continue;
CastAppInfo app_info(app_id); CastAppInfo app_info(app_id,
for (const auto& capability : CastDeviceCapabilitiesFromString(capabilities));
base::SplitStringPiece(capabilities, ",", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
app_info.required_capabilities |=
CastDeviceCapabilityFromString(capability);
}
app_infos.push_back(app_info); app_infos.push_back(app_info);
} }
...@@ -232,14 +264,20 @@ std::unique_ptr<CastMediaSource> ParseLegacyCastUrl( ...@@ -232,14 +264,20 @@ std::unique_ptr<CastMediaSource> ParseLegacyCastUrl(
return nullptr; return nullptr;
return CreateFromURLParams( return CreateFromURLParams(
source_id, app_infos, auto_join_policy, client_id, broadcast_namespace, source_id, app_infos, FindValueOr(params, "__castAutoJoinPolicy__", ""),
broadcast_message, FindValueOr(params, "__castDefaultActionPolicy__", ""),
base::TimeDelta::FromMilliseconds(launch_timeout_millis)); FindValueOr(params, "__castClientId__", ""),
FindValueOr(params, "__castBroadcastNamespace__", ""),
FindValueOr(params, "__castBroadcastMessage__", ""),
FindValueOr(params, "__castLaunchTimeout__", ""));
} }
} // namespace } // namespace
CastAppInfo::CastAppInfo(const std::string& app_id) : app_id(app_id) {} CastAppInfo::CastAppInfo(
const std::string& app_id,
BitwiseOr<cast_channel::CastDeviceCapability> required_capabilities)
: app_id(app_id), required_capabilities(required_capabilities) {}
CastAppInfo::~CastAppInfo() = default; CastAppInfo::~CastAppInfo() = default;
CastAppInfo::CastAppInfo(const CastAppInfo& other) = default; CastAppInfo::CastAppInfo(const CastAppInfo& other) = default;
...@@ -279,10 +317,12 @@ std::unique_ptr<CastMediaSource> CastMediaSource::FromAppId( ...@@ -279,10 +317,12 @@ std::unique_ptr<CastMediaSource> CastMediaSource::FromAppId(
CastMediaSource::CastMediaSource(const MediaSource::Id& source_id, CastMediaSource::CastMediaSource(const MediaSource::Id& source_id,
const std::vector<CastAppInfo>& app_infos, const std::vector<CastAppInfo>& app_infos,
AutoJoinPolicy auto_join_policy) AutoJoinPolicy auto_join_policy,
DefaultActionPolicy default_action_policy)
: source_id_(source_id), : source_id_(source_id),
app_infos_(app_infos), app_infos_(app_infos),
auto_join_policy_(auto_join_policy) {} auto_join_policy_(auto_join_policy),
default_action_policy_(default_action_policy) {}
CastMediaSource::CastMediaSource(const CastMediaSource& other) = default; CastMediaSource::CastMediaSource(const CastMediaSource& other) = default;
CastMediaSource::~CastMediaSource() = default; CastMediaSource::~CastMediaSource() = default;
......
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
#ifndef CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_ #ifndef CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_
#define CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_ #define CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_
#include <initializer_list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "base/logging.h"
#include "base/optional.h" #include "base/optional.h"
#include "chrome/common/media_router/media_source.h" #include "chrome/common/media_router/media_source.h"
#include "components/cast_channel/cast_message_util.h" #include "components/cast_channel/cast_message_util.h"
...@@ -26,9 +29,37 @@ static constexpr char kMultizoneLeaderAppId[] = "MultizoneLeader"; ...@@ -26,9 +29,37 @@ static constexpr char kMultizoneLeaderAppId[] = "MultizoneLeader";
static constexpr base::TimeDelta kDefaultLaunchTimeout = static constexpr base::TimeDelta kDefaultLaunchTimeout =
base::TimeDelta::FromSeconds(60); base::TimeDelta::FromSeconds(60);
// Class for storing a bitwise OR of enum values.
//
// TODO(jrw): Make values of cast_channel::CastDeviceCapability consecutive and
// store sets of values using a class like v8::base::EnumSet instead of this
// monstrosity.
template <typename E, typename T = std::underlying_type_t<E>>
class BitwiseOr {
public:
constexpr BitwiseOr() : bits_(0) {}
constexpr BitwiseOr(std::initializer_list<E> values) : bits_(0) {
for (E e : values)
Add(e);
}
bool empty() const { return bits_ == 0; }
void Add(E value) { bits_ |= Mask(value); }
bool operator==(const BitwiseOr& other) const { return bits_ == other.bits_; }
bool operator!=(const BitwiseOr& other) const { return *this != other; }
private:
static T Mask(E value) {
const T result = static_cast<T>(value);
DCHECK(static_cast<E>(result) == value);
return result;
}
T bits_;
};
// Represents a Cast app and its capabilitity requirements. // Represents a Cast app and its capabilitity requirements.
struct CastAppInfo { struct CastAppInfo {
explicit CastAppInfo(const std::string& app_id); explicit CastAppInfo(const std::string& app_id,
BitwiseOr<cast_channel::CastDeviceCapability> = {});
~CastAppInfo(); ~CastAppInfo();
CastAppInfo(const CastAppInfo& other); CastAppInfo(const CastAppInfo& other);
...@@ -36,22 +67,35 @@ struct CastAppInfo { ...@@ -36,22 +67,35 @@ struct CastAppInfo {
std::string app_id; std::string app_id;
// A bitset of capabilities required by the app. // A bitset of capabilities required by the app.
int required_capabilities = cast_channel::CastDeviceCapability::NONE; BitwiseOr<cast_channel::CastDeviceCapability> required_capabilities;
}; };
// Auto-join policy determines when the SDK will automatically connect a sender // Auto-join policy determines when the SDK will automatically connect a sender
// application to an existing session after API initialization. // application to an existing session after API initialization.
enum class AutoJoinPolicy { enum class AutoJoinPolicy {
// No automatic connection.
kPageScoped,
// Automatically connects when the session was started with the same app ID, // Automatically connects when the session was started with the same app ID,
// in the same tab and page origin. // in the same tab and page origin.
kTabAndOriginScoped, kTabAndOriginScoped,
// Automatically connects when the session was started with the same app ID // Automatically connects when the session was started with the same app ID
// and the same page origin (regardless of tab). // and the same page origin (regardless of tab).
kOriginScoped, kOriginScoped,
// No automatic connection. };
kPageScoped,
// No policy was specified. Generally treated the same as kPageScoped. // Default action policy determines when the SDK will automatically create a
kNone, // session after initializing the API. This also controls the default action
// for the tab in the Cast dialog.
enum class DefaultActionPolicy {
// If the tab containing the app is being cast when the API initializes, the
// SDK stops tab casting and automatically launches the app. The Cast dialog
// prompts the user to cast the app.
kCreateSession,
// No automatic launch is done after initializing the API, even if the tab is
// being cast. The Cast dialog prompts the user to mirror the tab (mirror,
// not cast, despite the name).
kCastThisTab,
}; };
// Represents a MediaSource parsed into structured, Cast specific data. The // Represents a MediaSource parsed into structured, Cast specific data. The
...@@ -69,7 +113,9 @@ class CastMediaSource { ...@@ -69,7 +113,9 @@ class CastMediaSource {
CastMediaSource(const MediaSource::Id& source_id, CastMediaSource(const MediaSource::Id& source_id,
const std::vector<CastAppInfo>& app_infos, const std::vector<CastAppInfo>& app_infos,
AutoJoinPolicy auto_join_policy = AutoJoinPolicy::kNone); AutoJoinPolicy auto_join_policy = AutoJoinPolicy::kPageScoped,
DefaultActionPolicy default_action_policy =
DefaultActionPolicy::kCreateSession);
CastMediaSource(const CastMediaSource& other); CastMediaSource(const CastMediaSource& other);
~CastMediaSource(); ~CastMediaSource();
...@@ -92,17 +138,17 @@ class CastMediaSource { ...@@ -92,17 +138,17 @@ class CastMediaSource {
const { const {
return broadcast_request_; return broadcast_request_;
} }
void set_broadcast_request(const cast_channel::BroadcastRequest& request) { void set_broadcast_request(const cast_channel::BroadcastRequest& request) {
broadcast_request_ = request; broadcast_request_ = request;
} }
AutoJoinPolicy auto_join_policy() const { return auto_join_policy_; } AutoJoinPolicy auto_join_policy() const { return auto_join_policy_; }
DefaultActionPolicy default_action_policy() { return default_action_policy_; }
private: private:
MediaSource::Id source_id_; MediaSource::Id source_id_;
std::vector<CastAppInfo> app_infos_; std::vector<CastAppInfo> app_infos_;
AutoJoinPolicy auto_join_policy_; AutoJoinPolicy auto_join_policy_;
DefaultActionPolicy default_action_policy_;
base::TimeDelta launch_timeout_ = kDefaultLaunchTimeout; base::TimeDelta launch_timeout_ = kDefaultLaunchTimeout;
// Empty if not set. // Empty if not set.
std::string client_id_; std::string client_id_;
......
...@@ -7,16 +7,38 @@ ...@@ -7,16 +7,38 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using cast_channel::CastDeviceCapability;
namespace media_router { namespace media_router {
TEST(CastMediaSourceTest, FromCastURLWithDefaults) {
MediaSource::Id source_id("cast:ABCDEFAB");
std::unique_ptr<CastMediaSource> source =
CastMediaSource::FromMediaSourceId(source_id);
ASSERT_TRUE(source);
EXPECT_EQ(source_id, source->source_id());
ASSERT_EQ(1u, source->app_infos().size());
const CastAppInfo& app_info = source->app_infos()[0];
EXPECT_EQ("ABCDEFAB", app_info.app_id);
EXPECT_TRUE(app_info.required_capabilities.empty());
const auto& broadcast_request = source->broadcast_request();
EXPECT_FALSE(broadcast_request);
EXPECT_EQ("", source->client_id());
EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCreateSession,
source->default_action_policy());
}
TEST(CastMediaSourceTest, FromCastURL) { TEST(CastMediaSourceTest, FromCastURL) {
MediaSource::Id source_id( MediaSource::Id source_id(
"cast:ABCDEFAB?capabilities=video_out,audio_out" "cast:ABCDEFAB?capabilities=video_out,audio_out"
"&broadcastNamespace=namespace" "&broadcastNamespace=namespace"
"&broadcastMessage=message" "&broadcastMessage=message%25"
"&clientId=12345" "&clientId=12345"
"&launchTimeout=30000" "&launchTimeout=30000"
"&autoJoinPolicy=tab_and_origin_scoped"); "&autoJoinPolicy=tab_and_origin_scoped"
"&defaultActionPolicy=cast_this_tab");
std::unique_ptr<CastMediaSource> source = std::unique_ptr<CastMediaSource> source =
CastMediaSource::FromMediaSourceId(source_id); CastMediaSource::FromMediaSourceId(source_id);
ASSERT_TRUE(source); ASSERT_TRUE(source);
...@@ -24,43 +46,49 @@ TEST(CastMediaSourceTest, FromCastURL) { ...@@ -24,43 +46,49 @@ TEST(CastMediaSourceTest, FromCastURL) {
ASSERT_EQ(1u, source->app_infos().size()); ASSERT_EQ(1u, source->app_infos().size());
const CastAppInfo& app_info = source->app_infos()[0]; const CastAppInfo& app_info = source->app_infos()[0];
EXPECT_EQ("ABCDEFAB", app_info.app_id); EXPECT_EQ("ABCDEFAB", app_info.app_id);
EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT | EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
cast_channel::CastDeviceCapability::AUDIO_OUT, CastDeviceCapability::AUDIO_OUT}),
app_info.required_capabilities); app_info.required_capabilities);
const auto& broadcast_request = source->broadcast_request(); const auto& broadcast_request = source->broadcast_request();
ASSERT_TRUE(broadcast_request); ASSERT_TRUE(broadcast_request);
EXPECT_EQ("namespace", broadcast_request->broadcast_namespace); EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
EXPECT_EQ("message", broadcast_request->message); EXPECT_EQ("message%", broadcast_request->message);
EXPECT_EQ("12345", source->client_id()); EXPECT_EQ("12345", source->client_id());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout()); EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kTabAndOriginScoped, source->auto_join_policy()); EXPECT_EQ(AutoJoinPolicy::kTabAndOriginScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
} }
TEST(CastMediaSourceTest, FromLegacyCastURL) { TEST(CastMediaSourceTest, FromLegacyCastURL) {
MediaSource::Id source_id( MediaSource::Id source_id(
"https://google.com/cast#__castAppId__=ABCDEFAB(video_out,audio_out)" "https://google.com/cast"
"#__castAppId__=ABCDEFAB(video_out,audio_out)"
"/__castAppId__=otherAppId"
"/__castBroadcastNamespace__=namespace" "/__castBroadcastNamespace__=namespace"
"/__castBroadcastMessage__=message" "/__castBroadcastMessage__=message%25"
"/__castClientId__=12345" "/__castClientId__=12345"
"/__castLaunchTimeout__=30000" "/__castLaunchTimeout__=30000"
"/__castAutoJoinPolicy__=origin_scoped"); "/__castAutoJoinPolicy__=origin_scoped"
"/__castDefaultActionPolicy__=cast_this_tab");
std::unique_ptr<CastMediaSource> source = std::unique_ptr<CastMediaSource> source =
CastMediaSource::FromMediaSourceId(source_id); CastMediaSource::FromMediaSourceId(source_id);
ASSERT_TRUE(source); ASSERT_TRUE(source);
EXPECT_EQ(source_id, source->source_id()); EXPECT_EQ(source_id, source->source_id());
ASSERT_EQ(1u, source->app_infos().size()); ASSERT_EQ(2u, source->app_infos().size());
const CastAppInfo& app_info = source->app_infos()[0]; const CastAppInfo& app_info = source->app_infos()[0];
EXPECT_EQ("ABCDEFAB", app_info.app_id); EXPECT_EQ("ABCDEFAB", app_info.app_id);
EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT | EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
cast_channel::CastDeviceCapability::AUDIO_OUT, CastDeviceCapability::AUDIO_OUT}),
app_info.required_capabilities); app_info.required_capabilities);
EXPECT_EQ("otherAppId", source->app_infos()[1].app_id);
const auto& broadcast_request = source->broadcast_request(); const auto& broadcast_request = source->broadcast_request();
ASSERT_TRUE(broadcast_request); ASSERT_TRUE(broadcast_request);
EXPECT_EQ("namespace", broadcast_request->broadcast_namespace); EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
EXPECT_EQ("message", broadcast_request->message); EXPECT_EQ("message%", broadcast_request->message);
EXPECT_EQ("12345", source->client_id()); EXPECT_EQ("12345", source->client_id());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout()); EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kOriginScoped, source->auto_join_policy()); EXPECT_EQ(AutoJoinPolicy::kOriginScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
} }
TEST(CastMediaSourceTest, FromPresentationURL) { TEST(CastMediaSourceTest, FromPresentationURL) {
...@@ -74,7 +102,9 @@ TEST(CastMediaSourceTest, FromPresentationURL) { ...@@ -74,7 +102,9 @@ TEST(CastMediaSourceTest, FromPresentationURL) {
EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id); EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
EXPECT_TRUE(source->client_id().empty()); EXPECT_TRUE(source->client_id().empty());
EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout()); EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kNone, source->auto_join_policy()); EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCreateSession,
source->default_action_policy());
} }
TEST(CastMediaSourceTest, FromMirroringURN) { TEST(CastMediaSourceTest, FromMirroringURN) {
...@@ -88,7 +118,9 @@ TEST(CastMediaSourceTest, FromMirroringURN) { ...@@ -88,7 +118,9 @@ TEST(CastMediaSourceTest, FromMirroringURN) {
EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id); EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
EXPECT_TRUE(source->client_id().empty()); EXPECT_TRUE(source->client_id().empty());
EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout()); EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kNone, source->auto_join_policy()); EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCreateSession,
source->default_action_policy());
} }
TEST(CastMediaSourceTest, FromDesktopUrn) { TEST(CastMediaSourceTest, FromDesktopUrn) {
...@@ -101,7 +133,9 @@ TEST(CastMediaSourceTest, FromDesktopUrn) { ...@@ -101,7 +133,9 @@ TEST(CastMediaSourceTest, FromDesktopUrn) {
EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id); EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
EXPECT_TRUE(source->client_id().empty()); EXPECT_TRUE(source->client_id().empty());
EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout()); EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kNone, source->auto_join_policy()); EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCreateSession,
source->default_action_policy());
} }
TEST(CastMediaSourceTest, FromInvalidSource) { TEST(CastMediaSourceTest, FromInvalidSource) {
......
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