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
......@@ -5,10 +5,13 @@
#ifndef 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 <string>
#include <type_traits>
#include <vector>
#include "base/logging.h"
#include "base/optional.h"
#include "chrome/common/media_router/media_source.h"
#include "components/cast_channel/cast_message_util.h"
......@@ -26,9 +29,37 @@ static constexpr char kMultizoneLeaderAppId[] = "MultizoneLeader";
static constexpr base::TimeDelta kDefaultLaunchTimeout =
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.
struct CastAppInfo {
explicit CastAppInfo(const std::string& app_id);
explicit CastAppInfo(const std::string& app_id,
BitwiseOr<cast_channel::CastDeviceCapability> = {});
~CastAppInfo();
CastAppInfo(const CastAppInfo& other);
......@@ -36,22 +67,35 @@ struct CastAppInfo {
std::string app_id;
// 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
// application to an existing session after API initialization.
enum class AutoJoinPolicy {
// No automatic connection.
kPageScoped,
// Automatically connects when the session was started with the same app ID,
// in the same tab and page origin.
kTabAndOriginScoped,
// Automatically connects when the session was started with the same app ID
// and the same page origin (regardless of tab).
kOriginScoped,
// No automatic connection.
kPageScoped,
// No policy was specified. Generally treated the same as kPageScoped.
kNone,
};
// Default action policy determines when the SDK will automatically create a
// 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
......@@ -69,7 +113,9 @@ class CastMediaSource {
CastMediaSource(const MediaSource::Id& source_id,
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();
......@@ -92,17 +138,17 @@ class CastMediaSource {
const {
return broadcast_request_;
}
void set_broadcast_request(const cast_channel::BroadcastRequest& request) {
broadcast_request_ = request;
}
AutoJoinPolicy auto_join_policy() const { return auto_join_policy_; }
DefaultActionPolicy default_action_policy() { return default_action_policy_; }
private:
MediaSource::Id source_id_;
std::vector<CastAppInfo> app_infos_;
AutoJoinPolicy auto_join_policy_;
DefaultActionPolicy default_action_policy_;
base::TimeDelta launch_timeout_ = kDefaultLaunchTimeout;
// Empty if not set.
std::string client_id_;
......
......@@ -7,16 +7,38 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using cast_channel::CastDeviceCapability;
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) {
MediaSource::Id source_id(
"cast:ABCDEFAB?capabilities=video_out,audio_out"
"&broadcastNamespace=namespace"
"&broadcastMessage=message"
"&broadcastMessage=message%25"
"&clientId=12345"
"&launchTimeout=30000"
"&autoJoinPolicy=tab_and_origin_scoped");
"&autoJoinPolicy=tab_and_origin_scoped"
"&defaultActionPolicy=cast_this_tab");
std::unique_ptr<CastMediaSource> source =
CastMediaSource::FromMediaSourceId(source_id);
ASSERT_TRUE(source);
......@@ -24,43 +46,49 @@ TEST(CastMediaSourceTest, FromCastURL) {
ASSERT_EQ(1u, source->app_infos().size());
const CastAppInfo& app_info = source->app_infos()[0];
EXPECT_EQ("ABCDEFAB", app_info.app_id);
EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT |
cast_channel::CastDeviceCapability::AUDIO_OUT,
EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
CastDeviceCapability::AUDIO_OUT}),
app_info.required_capabilities);
const auto& broadcast_request = source->broadcast_request();
ASSERT_TRUE(broadcast_request);
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(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kTabAndOriginScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
}
TEST(CastMediaSourceTest, FromLegacyCastURL) {
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"
"/__castBroadcastMessage__=message"
"/__castBroadcastMessage__=message%25"
"/__castClientId__=12345"
"/__castLaunchTimeout__=30000"
"/__castAutoJoinPolicy__=origin_scoped");
"/__castAutoJoinPolicy__=origin_scoped"
"/__castDefaultActionPolicy__=cast_this_tab");
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());
ASSERT_EQ(2u, source->app_infos().size());
const CastAppInfo& app_info = source->app_infos()[0];
EXPECT_EQ("ABCDEFAB", app_info.app_id);
EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT |
cast_channel::CastDeviceCapability::AUDIO_OUT,
EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
CastDeviceCapability::AUDIO_OUT}),
app_info.required_capabilities);
EXPECT_EQ("otherAppId", source->app_infos()[1].app_id);
const auto& broadcast_request = source->broadcast_request();
ASSERT_TRUE(broadcast_request);
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(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
EXPECT_EQ(AutoJoinPolicy::kOriginScoped, source->auto_join_policy());
EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
}
TEST(CastMediaSourceTest, FromPresentationURL) {
......@@ -74,7 +102,9 @@ TEST(CastMediaSourceTest, FromPresentationURL) {
EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
EXPECT_TRUE(source->client_id().empty());
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) {
......@@ -88,7 +118,9 @@ TEST(CastMediaSourceTest, FromMirroringURN) {
EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
EXPECT_TRUE(source->client_id().empty());
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) {
......@@ -101,7 +133,9 @@ TEST(CastMediaSourceTest, FromDesktopUrn) {
EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
EXPECT_TRUE(source->client_id().empty());
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) {
......
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