diff options
Diffstat (limited to 'chromium/chrome/common/media_router/providers')
3 files changed, 97 insertions, 12 deletions
diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc b/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc index 97002d0fd2a..c7fe6bf2e93 100644 --- a/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc +++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc @@ -61,6 +61,7 @@ const EnumTable<CastDeviceCapability> EnumTable<CastDeviceCapability>::instance( template <> const EnumTable<ReceiverAppType> EnumTable<ReceiverAppType>::instance( { + {ReceiverAppType::kOther, "OTHER"}, {ReceiverAppType::kWeb, "WEB"}, {ReceiverAppType::kAndroidTv, "ANDROID_TV"}, }, @@ -70,6 +71,9 @@ const EnumTable<ReceiverAppType> EnumTable<ReceiverAppType>::instance( namespace media_router { +// The maximum length of presentation URL is 64KB. +constexpr int kMaxCastPresentationUrlLength = 64 * 1024; + namespace { // A nonmember version of base::Optional::value_or that works on pointers as @@ -188,8 +192,8 @@ std::unique_ptr<CastMediaSource> CastMediaSourceForTabMirroring( const MediaSource::Id& source_id) { return std::make_unique<CastMediaSource>( source_id, - std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId), - CastAppInfo(kCastStreamingAudioAppId)})); + std::vector<CastAppInfo>({CastAppInfo::ForCastStreaming(), + CastAppInfo::ForCastStreamingAudio()})); } std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring( @@ -197,7 +201,7 @@ std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring( // TODO(https://crbug.com/849335): Add back audio-only devices for desktop // mirroring when proper support is implemented. return std::make_unique<CastMediaSource>( - source_id, std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId)})); + source_id, std::vector<CastAppInfo>({CastAppInfo::ForCastStreaming()})); } // The logic shared by ParseCastUrl() and ParseLegacyCastUrl(). @@ -210,6 +214,8 @@ std::unique_ptr<CastMediaSource> CreateFromURLParams( const std::string& broadcast_namespace, const std::string& encoded_broadcast_message, const std::string& launch_timeout_str, + const std::string& target_playout_delay_millis_str, + const std::string& audio_capture_str, const std::vector<ReceiverAppType>& supported_app_types, const std::string& app_params) { if (app_infos.empty()) @@ -227,13 +233,24 @@ std::unique_ptr<CastMediaSource> CreateFromURLParams( broadcast_namespace, DecodeURLComponent(encoded_broadcast_message))); } - int launch_timeout_millis; + int launch_timeout_millis = 0; if (base::StringToInt(launch_timeout_str, &launch_timeout_millis) && launch_timeout_millis > 0) { cast_source->set_launch_timeout( base::TimeDelta::FromMilliseconds(launch_timeout_millis)); } + int target_playout_delay_millis = 0; + if (base::StringToInt(target_playout_delay_millis_str, + &target_playout_delay_millis) && + target_playout_delay_millis > 0) { + cast_source->set_target_playout_delay( + base::TimeDelta::FromMilliseconds(target_playout_delay_millis)); + } + + if (audio_capture_str == "0") + cast_source->set_allow_audio_capture(false); + if (!supported_app_types.empty()) cast_source->set_supported_app_types(supported_app_types); cast_source->set_app_params(app_params); @@ -259,6 +276,8 @@ std::unique_ptr<CastMediaSource> ParseCastUrl(const MediaSource::Id& source_id, FindValueOr(params, "broadcastNamespace", ""), FindValueOr(params, "broadcastMessage", ""), FindValueOr(params, "launchTimeout", ""), + FindValueOr(params, "streamingTargetPlayoutDelayMillis", ""), + FindValueOr(params, "streamingCaptureAudio", ""), SupportedAppTypesFromString(FindValueOr(params, "supportedAppTypes", "")), FindValueOr(params, "appParams", "")); } @@ -318,6 +337,8 @@ std::unique_ptr<CastMediaSource> ParseLegacyCastUrl( FindValueOr(params, "__castBroadcastNamespace__", ""), FindValueOr(params, "__castBroadcastMessage__", ""), FindValueOr(params, "__castLaunchTimeout__", ""), + /* target_playout_delay_millis_str */ "", + /* audio_capture */ "", /* supported_app_types */ {}, /* appParams */ ""); } @@ -339,27 +360,45 @@ bool IsAutoJoinAllowed(AutoJoinPolicy policy, } } +bool IsSiteInitiatedMirroringSource(const MediaSource::Id& source_id) { + return base::StartsWith(source_id, kMirroringAppUri, + base::CompareCase::SENSITIVE); +} + 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(const CastAppInfo& other) = default; // static +CastAppInfo CastAppInfo::ForCastStreaming() { + return CastAppInfo(kCastStreamingAppId, {CastDeviceCapability::VIDEO_OUT, + CastDeviceCapability::AUDIO_OUT}); +} + +// static +CastAppInfo CastAppInfo::ForCastStreamingAudio() { + return CastAppInfo(kCastStreamingAudioAppId, + {CastDeviceCapability::AUDIO_OUT}); +} + +// static std::unique_ptr<CastMediaSource> CastMediaSource::FromMediaSource( const MediaSource& source) { - if (source.IsTabMirroringSource()) + if (source.IsTabMirroringSource() || source.IsLocalFileSource()) return CastMediaSourceForTabMirroring(source.id()); if (source.IsDesktopMirroringSource()) return CastMediaSourceForDesktopMirroring(source.id()); const GURL& url = source.url(); - if (!url.is_valid()) - return nullptr; + if (!url.is_valid() || url.spec().length() > kMaxCastPresentationUrlLength) + return nullptr; if (url.SchemeIs(kCastPresentationUrlScheme)) { return ParseCastUrl(source.id(), url); } else if (IsLegacyCastPresentationUrl(url)) { diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source.h b/chromium/chrome/common/media_router/providers/cast/cast_media_source.h index 09c04496b2f..ce8f7b9ef98 100644 --- a/chromium/chrome/common/media_router/providers/cast/cast_media_source.h +++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source.h @@ -11,7 +11,7 @@ #include <type_traits> #include <vector> -#include "base/logging.h" +#include "base/check.h" #include "base/optional.h" #include "chrome/common/media_router/media_source.h" #include "components/cast_channel/cast_message_util.h" @@ -28,6 +28,13 @@ static constexpr char kCastStreamingAudioAppId[] = "85CDB22F"; // message. static constexpr char kMultizoneLeaderAppId[] = "MultizoneLeader"; +static const constexpr char* const kMultizoneMemberAppIds[] = { + kMultizoneLeaderAppId, + "531A4F84", // MultizoneLeader + "MultizoneFollower", + "705D30C6" // MultizoneFollower +}; + static constexpr base::TimeDelta kDefaultLaunchTimeout = base::TimeDelta::FromSeconds(60); @@ -44,12 +51,20 @@ class BitwiseOr { for (E e : values) Add(e); } + static constexpr BitwiseOr FromBits(T bits) { return BitwiseOr(bits); } bool empty() const { return bits_ == 0; } + T bits() const { return bits_; } void Add(E value) { bits_ |= Mask(value); } + bool Has(E value) const { return (bits_ & Mask(value)) != 0; } + bool HasAll(const BitwiseOr& other) const { + return (bits_ & other.bits_) == other.bits_; + } bool operator==(const BitwiseOr& other) const { return bits_ == other.bits_; } bool operator!=(const BitwiseOr& other) const { return *this != other; } private: + explicit constexpr BitwiseOr(T bits) : bits_(bits) {} + static T Mask(E value) { const T result = static_cast<T>(value); DCHECK(static_cast<E>(result) == value); @@ -60,12 +75,16 @@ class BitwiseOr { // Represents a Cast app and its capabilitity requirements. struct CastAppInfo { - explicit CastAppInfo(const std::string& app_id, - BitwiseOr<cast_channel::CastDeviceCapability> = {}); + explicit CastAppInfo( + const std::string& app_id, + BitwiseOr<cast_channel::CastDeviceCapability> required_capabilities); ~CastAppInfo(); CastAppInfo(const CastAppInfo& other); + static CastAppInfo ForCastStreaming(); + static CastAppInfo ForCastStreamingAudio(); + std::string app_id; // A bitset of capabilities required by the app. @@ -114,6 +133,9 @@ bool IsAutoJoinAllowed(AutoJoinPolicy policy, const url::Origin& origin2, int tab_id2); +// Returns true if |source_id| is a valid origin for site-initiated mirroring. +bool IsSiteInitiatedMirroringSource(const MediaSource::Id& source_id); + // Represents a MediaSource parsed into structured, Cast specific data. The // following MediaSources can be parsed into CastMediaSource: // - Cast Presentation URLs @@ -165,6 +187,17 @@ class CastMediaSource { DefaultActionPolicy default_action_policy() const { return default_action_policy_; } + base::Optional<base::TimeDelta> target_playout_delay() const { + return target_playout_delay_; + } + void set_target_playout_delay( + const base::Optional<base::TimeDelta>& target_playout_delay) { + target_playout_delay_ = target_playout_delay; + } + bool allow_audio_capture() const { return allow_audio_capture_; } + void set_allow_audio_capture(bool allow_audio_capture) { + allow_audio_capture_ = allow_audio_capture; + } const std::string& app_params() const { return app_params_; } void set_app_params(const std::string& app_params) { app_params_ = app_params; @@ -180,9 +213,11 @@ class CastMediaSource { AutoJoinPolicy auto_join_policy_; DefaultActionPolicy default_action_policy_; base::TimeDelta launch_timeout_ = kDefaultLaunchTimeout; - // Empty if not set. + // Optional parameters. std::string client_id_; base::Optional<cast_channel::BroadcastRequest> broadcast_request_; + base::Optional<base::TimeDelta> target_playout_delay_; + bool allow_audio_capture_ = true; std::vector<ReceiverAppType> supported_app_types_ = {ReceiverAppType::kWeb}; std::string app_params_; }; diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc b/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc index 42c5c660f7a..03ebc375c99 100644 --- a/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc +++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc @@ -30,6 +30,8 @@ TEST(CastMediaSourceTest, FromCastURLWithDefaults) { EXPECT_EQ(DefaultActionPolicy::kCreateSession, source->default_action_policy()); EXPECT_EQ(ReceiverAppType::kWeb, source->supported_app_types()[0]); + EXPECT_EQ(base::nullopt, source->target_playout_delay()); + EXPECT_EQ(true, source->allow_audio_capture()); } TEST(CastMediaSourceTest, FromCastURL) { @@ -42,7 +44,9 @@ TEST(CastMediaSourceTest, FromCastURL) { "&autoJoinPolicy=tab_and_origin_scoped" "&defaultActionPolicy=cast_this_tab" "&appParams=appParams" - "&supportedAppTypes=ANDROID_TV,WEB"); + "&supportedAppTypes=ANDROID_TV,WEB" + "&streamingTargetPlayoutDelayMillis=42" + "&streamingCaptureAudio=0"); std::unique_ptr<CastMediaSource> source = CastMediaSource::FromMediaSourceId(source_id); ASSERT_TRUE(source); @@ -64,6 +68,9 @@ TEST(CastMediaSourceTest, FromCastURL) { EXPECT_EQ(ReceiverAppType::kAndroidTv, source->supported_app_types()[0]); EXPECT_EQ(ReceiverAppType::kWeb, source->supported_app_types()[1]); EXPECT_EQ("appParams", source->app_params()); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(42), + source->target_playout_delay()); + EXPECT_EQ(false, source->allow_audio_capture()); } TEST(CastMediaSourceTest, FromLegacyCastURL) { @@ -159,6 +166,10 @@ TEST(CastMediaSourceTest, FromInvalidSource) { EXPECT_FALSE(CastMediaSource::FromMediaSourceId("cast:?param=foo")); EXPECT_FALSE(CastMediaSource::FromMediaSourceId( "https://google.com/cast#__castAppId__=/param=foo")); + // URL spec exceeds maximum size limit 64KB. + int length = 64 * 1024 + 1; + std::string invalidURL(length, 'a'); + EXPECT_FALSE(CastMediaSource::FromMediaSourceId("cast:appid?" + invalidURL)); } } // namespace media_router |