diff options
Diffstat (limited to 'cast/streaming/receiver_session_unittest.cc')
-rw-r--r-- | cast/streaming/receiver_session_unittest.cc | 602 |
1 files changed, 557 insertions, 45 deletions
diff --git a/cast/streaming/receiver_session_unittest.cc b/cast/streaming/receiver_session_unittest.cc index 1914cbd5..098695a8 100644 --- a/cast/streaming/receiver_session_unittest.cc +++ b/cast/streaming/receiver_session_unittest.cc @@ -15,6 +15,7 @@ #include "platform/test/fake_clock.h" #include "platform/test/fake_task_runner.h" #include "util/chrono_helpers.h" +#include "util/json/json_serialization.h" using ::testing::_; using ::testing::InSequence; @@ -33,7 +34,6 @@ constexpr char kValidOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [ { "index": 31337, @@ -78,6 +78,26 @@ constexpr char kValidOfferMessage[] = R"({ ] }, { + "index": 31339, + "type": "video_source", + "codecName": "hevc", + "codecParameter": "hev1.1.6.L150.B0", + "rtpProfile": "cast", + "rtpPayloadType": 127, + "ssrc": 19088746, + "maxFrameRate": "120", + "timeBase": "1/90000", + "maxBitRate": 5000000, + "aesKey": "040d756791711fd3adb939066e6d8690", + "aesIvMask": "9ff0f022a959150e70a2d05a6c184aed", + "resolutions": [ + { + "width": 1920, + "height": 1080 + } + ] + }, + { "index": 1337, "type": "audio_source", "codecName": "opus", @@ -94,12 +114,53 @@ constexpr char kValidOfferMessage[] = R"({ } })"; +constexpr char kValidRemotingOfferMessage[] = R"({ + "type": "OFFER", + "seqNum": 419, + "offer": { + "castMode": "remoting", + "supportedStreams": [ + { + "index": 31339, + "type": "video_source", + "codecName": "REMOTE_VIDEO", + "rtpProfile": "cast", + "rtpPayloadType": 127, + "ssrc": 19088745, + "maxFrameRate": "60000/1000", + "timeBase": "1/90000", + "maxBitRate": 5432101, + "aesKey": "040d756791711fd3adb939066e6d8690", + "aesIvMask": "9ff0f022a959150e70a2d05a6c184aed", + "resolutions": [ + { + "width": 1920, + "height":1080 + } + ] + }, + { + "index": 31340, + "type": "audio_source", + "codecName": "REMOTE_AUDIO", + "rtpProfile": "cast", + "rtpPayloadType": 97, + "ssrc": 19088747, + "bitRate": 125000, + "timeBase": "1/48000", + "channels": 2, + "aesKey": "51027e4e2347cbcb49d57ef10177aebc", + "aesIvMask": "7f12a19be62a36c04ae4116caaeff6d1" + } + ] + } +})"; + constexpr char kNoAudioOfferMessage[] = R"({ "type": "OFFER", "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [ { "index": 31338, @@ -131,7 +192,6 @@ constexpr char kInvalidCodecOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [ { "index": 31338, @@ -163,7 +223,6 @@ constexpr char kNoVideoOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [ { "index": 1337, @@ -187,7 +246,6 @@ constexpr char kNoAudioOrVideoOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [] } })"; @@ -197,7 +255,6 @@ constexpr char kInvalidJsonOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [ } })"; @@ -211,7 +268,6 @@ constexpr char kMissingSeqNumOfferMessage[] = R"({ "type": "OFFER", "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": [] } })"; @@ -221,7 +277,6 @@ constexpr char kValidJsonInvalidFormatOfferMessage[] = R"({ "seqNum": 1337, "offer": { "castMode": "mirroring", - "receiverGetStatus": true, "supportedStreams": "anything" } })"; @@ -246,17 +301,36 @@ constexpr char kInvalidTypeMessage[] = R"({ "seqNum": 1337 })"; +constexpr char kGetCapabilitiesMessage[] = R"({ + "seqNum": 820263770, + "type": "GET_CAPABILITIES" +})"; + +constexpr char kRpcMessage[] = R"({ + "rpc" : "CGQQnBiCGQgSAggMGgIIBg==", + "seqNum" : 2, + "type" : "RPC" +})"; + class FakeClient : public ReceiverSession::Client { public: MOCK_METHOD(void, - OnMirroringNegotiated, + OnNegotiated, (const ReceiverSession*, ReceiverSession::ConfiguredReceivers), (override)); MOCK_METHOD(void, + OnRemotingNegotiated, + (const ReceiverSession*, ReceiverSession::RemotingNegotiation), + (override)); + MOCK_METHOD(void, OnReceiversDestroying, (const ReceiverSession*, ReceiversDestroyingReason), (override)); MOCK_METHOD(void, OnError, (const ReceiverSession*, Error error), (override)); + MOCK_METHOD(bool, + SupportsCodecParameter, + (const std::string& parameter), + (override)); }; void ExpectIsErrorAnswerMessage(const ErrorOr<Json::Value>& message_or_error) { @@ -288,12 +362,17 @@ class ReceiverSessionTest : public ::testing::Test { return environment_; } - void SetUp() { + void SetUp() { SetUpWithPreferences(ReceiverSession::Preferences{}); } + + // Since preferences are constant throughout the life of a session, + // changing them requires configuring a new session. + void SetUpWithPreferences(ReceiverSession::Preferences preferences) { + session_.reset(); message_port_ = std::make_unique<SimpleMessagePort>("sender-12345"); environment_ = MakeEnvironment(); - session_ = std::make_unique<ReceiverSession>( - &client_, environment_.get(), message_port_.get(), - ReceiverSession::Preferences{}); + session_ = std::make_unique<ReceiverSession>(&client_, environment_.get(), + message_port_.get(), + std::move(preferences)); } protected: @@ -315,7 +394,7 @@ class ReceiverSessionTest : public ::testing::Test { TEST_F(ReceiverSessionTest, CanNegotiateWithDefaultPreferences) { InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)) + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)) .WillOnce([](const ReceiverSession* session_, ReceiverSession::ConfiguredReceivers cr) { EXPECT_TRUE(cr.audio_receiver); @@ -364,9 +443,6 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithDefaultPreferences) { EXPECT_LT(0, answer_body["udpPort"].asInt()); EXPECT_GT(65535, answer_body["udpPort"].asInt()); - // Get status should always be false, as we have no plans to implement it. - EXPECT_EQ(false, answer_body["receiverGetStatus"].asBool()); - // Constraints and display should not be present with no preferences. EXPECT_TRUE(answer_body["constraints"].isNull()); EXPECT_TRUE(answer_body["display"].isNull()); @@ -378,7 +454,7 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomCodecPreferences) { ReceiverSession::Preferences{{VideoCodec::kVp9}, {AudioCodec::kOpus}}); InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(&session, _)) + EXPECT_CALL(client_, OnNegotiated(&session, _)) .WillOnce([](const ReceiverSession* session_, ReceiverSession::ConfiguredReceivers cr) { EXPECT_TRUE(cr.audio_receiver); @@ -400,28 +476,88 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomCodecPreferences) { message_port_->ReceiveMessage(kValidOfferMessage); } -TEST_F(ReceiverSessionTest, CanNegotiateWithCustomConstraints) { - auto constraints = std::make_unique<Constraints>(Constraints{ - AudioConstraints{48001, 2, 32001, 32002, milliseconds(3001)}, - VideoConstraints{3.14159, - absl::optional<Dimensions>( - Dimensions{320, 240, SimpleFraction{24, 1}}), - Dimensions{1920, 1080, SimpleFraction{144, 1}}, 300000, - 90000000, milliseconds(1000)}}); +TEST_F(ReceiverSessionTest, RejectsStreamWithUnsupportedCodecParameter) { + ReceiverSession::Preferences preferences({VideoCodec::kHevc}, + {AudioCodec::kOpus}); + EXPECT_CALL(client_, SupportsCodecParameter(_)).WillRepeatedly(Return(false)); + ReceiverSession session(&client_, environment_.get(), message_port_.get(), + preferences); + InSequence s; + EXPECT_CALL(client_, OnNegotiated(&session, _)) + .WillOnce([](const ReceiverSession* session_, + ReceiverSession::ConfiguredReceivers cr) { + EXPECT_FALSE(cr.video_receiver); + }); + EXPECT_CALL(client_, OnReceiversDestroying( + &session, ReceiverSession::Client::kEndOfSession)); + message_port_->ReceiveMessage(kValidOfferMessage); +} + +TEST_F(ReceiverSessionTest, AcceptsStreamWithNoCodecParameter) { + ReceiverSession::Preferences preferences( + {VideoCodec::kHevc, VideoCodec::kVp9}, {AudioCodec::kOpus}); + EXPECT_CALL(client_, SupportsCodecParameter(_)).WillRepeatedly(Return(false)); + + ReceiverSession session(&client_, environment_.get(), message_port_.get(), + std::move(preferences)); + InSequence s; + EXPECT_CALL(client_, OnNegotiated(&session, _)) + .WillOnce([](const ReceiverSession* session_, + ReceiverSession::ConfiguredReceivers cr) { + EXPECT_TRUE(cr.video_receiver); + EXPECT_EQ(cr.video_config.codec, VideoCodec::kVp9); + }); + EXPECT_CALL(client_, OnReceiversDestroying( + &session, ReceiverSession::Client::kEndOfSession)); + message_port_->ReceiveMessage(kValidOfferMessage); +} + +TEST_F(ReceiverSessionTest, AcceptsStreamWithMatchingParameter) { + ReceiverSession::Preferences preferences({VideoCodec::kHevc}, + {AudioCodec::kOpus}); + EXPECT_CALL(client_, SupportsCodecParameter(_)) + .WillRepeatedly( + [](const std::string& param) { return param == "hev1.1.6.L150.B0"; }); + + ReceiverSession session(&client_, environment_.get(), message_port_.get(), + std::move(preferences)); + InSequence s; + EXPECT_CALL(client_, OnNegotiated(&session, _)) + .WillOnce([](const ReceiverSession* session_, + ReceiverSession::ConfiguredReceivers cr) { + EXPECT_TRUE(cr.video_receiver); + EXPECT_EQ(cr.video_config.codec, VideoCodec::kHevc); + }); + EXPECT_CALL(client_, OnReceiversDestroying( + &session, ReceiverSession::Client::kEndOfSession)); + message_port_->ReceiveMessage(kValidOfferMessage); +} - auto display = std::make_unique<DisplayDescription>(DisplayDescription{ - absl::optional<Dimensions>(Dimensions{640, 480, SimpleFraction{60, 1}}), - absl::optional<AspectRatio>(AspectRatio{16, 9}), - absl::optional<AspectRatioConstraint>(AspectRatioConstraint::kFixed)}); +TEST_F(ReceiverSessionTest, CanNegotiateWithLimits) { + std::vector<ReceiverSession::AudioLimits> audio_limits = { + {false, AudioCodec::kOpus, 48001, 2, 32001, 32002, milliseconds(3001)}}; + std::vector<ReceiverSession::VideoLimits> video_limits = { + {true, + VideoCodec::kVp9, + 62208000, + {1920, 1080, {144, 1}}, + 300000, + 90000000, + milliseconds(1000)}}; + + auto display = + std::make_unique<ReceiverSession::Display>(ReceiverSession::Display{ + {640, 480, {60, 1}}, false /* can scale content */}); ReceiverSession session(&client_, environment_.get(), message_port_.get(), ReceiverSession::Preferences{{VideoCodec::kVp9}, {AudioCodec::kOpus}, - std::move(constraints), + std::move(audio_limits), + std::move(video_limits), std::move(display)}); InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(&session, _)); + EXPECT_CALL(client_, OnNegotiated(&session, _)); EXPECT_CALL(client_, OnReceiversDestroying( &session, ReceiverSession::Client::kEndOfSession)); message_port_->ReceiveMessage(kValidOfferMessage); @@ -434,14 +570,13 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomConstraints) { const Json::Value answer = std::move(message_body.value()); const Json::Value& answer_body = answer["answer"]; - ASSERT_TRUE(answer_body.isObject()); + ASSERT_TRUE(answer_body.isObject()) << messages[0]; // Constraints and display should be valid with valid preferences. ASSERT_FALSE(answer_body["constraints"].isNull()); ASSERT_FALSE(answer_body["display"].isNull()); const Json::Value& display_json = answer_body["display"]; - EXPECT_EQ("16:9", display_json["aspectRatio"].asString()); EXPECT_EQ("60", display_json["dimensions"]["frameRate"].asString()); EXPECT_EQ(640, display_json["dimensions"]["width"].asInt()); EXPECT_EQ(480, display_json["dimensions"]["height"].asInt()); @@ -465,16 +600,12 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomConstraints) { EXPECT_EQ("144", video["maxDimensions"]["frameRate"].asString()); EXPECT_EQ(1920, video["maxDimensions"]["width"].asInt()); EXPECT_EQ(1080, video["maxDimensions"]["height"].asInt()); - EXPECT_DOUBLE_EQ(3.14159, video["maxPixelsPerSecond"].asDouble()); EXPECT_EQ(300000, video["minBitRate"].asInt()); - EXPECT_EQ("24", video["minDimensions"]["frameRate"].asString()); - EXPECT_EQ(320, video["minDimensions"]["width"].asInt()); - EXPECT_EQ(240, video["minDimensions"]["height"].asInt()); } TEST_F(ReceiverSessionTest, HandlesNoValidAudioStream) { InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)); + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)); EXPECT_CALL(client_, OnReceiversDestroying(session_.get(), ReceiverSession::Client::kEndOfSession)); @@ -511,7 +642,7 @@ TEST_F(ReceiverSessionTest, HandlesInvalidCodec) { TEST_F(ReceiverSessionTest, HandlesNoValidVideoStream) { InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)); + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)); EXPECT_CALL(client_, OnReceiversDestroying(session_.get(), ReceiverSession::Client::kEndOfSession)); @@ -533,8 +664,7 @@ TEST_F(ReceiverSessionTest, HandlesNoValidVideoStream) { } TEST_F(ReceiverSessionTest, HandlesNoValidStreams) { - // We shouldn't call OnMirroringNegotiated if we failed to negotiate any - // streams. + // We shouldn't call OnNegotiated if we failed to negotiate any streams. message_port_->ReceiveMessage(kNoAudioOrVideoOfferMessage); AssertGotAnErrorAnswerResponse(); } @@ -596,11 +726,11 @@ TEST_F(ReceiverSessionTest, DoesNotCrashOnMessagePortError) { TEST_F(ReceiverSessionTest, NotifiesReceiverDestruction) { InSequence s; - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)); + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)); EXPECT_CALL(client_, OnReceiversDestroying(session_.get(), ReceiverSession::Client::kRenegotiated)); - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)); + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)); EXPECT_CALL(client_, OnReceiversDestroying(session_.get(), ReceiverSession::Client::kEndOfSession)); @@ -638,7 +768,7 @@ TEST_F(ReceiverSessionTest, DelaysAnswerUntilEnvironmentIsReady) { // state() will not be called again--we just need to get the bind event. EXPECT_CALL(*environment_, GetBoundLocalEndpoint()) .WillOnce(Return(IPEndpoint{{10, 0, 0, 2}, 4567})); - EXPECT_CALL(client_, OnMirroringNegotiated(session_.get(), _)); + EXPECT_CALL(client_, OnNegotiated(session_.get(), _)); EXPECT_CALL(client_, OnReceiversDestroying(session_.get(), ReceiverSession::Client::kEndOfSession)); @@ -691,5 +821,387 @@ TEST_F(ReceiverSessionTest, ReturnsErrorAnswerIfEnvironmentIsInvalidated) { EXPECT_EQ("error", message_body.value()["result"].asString()); } +TEST_F(ReceiverSessionTest, ReturnsErrorCapabilitiesIfRemotingDisabled) { + message_port_->ReceiveMessage(kGetCapabilitiesMessage); + const auto& messages = message_port_->posted_messages(); + ASSERT_EQ(1u, messages.size()); + + // We should have an error response. + auto message_body = json::Parse(messages[0]); + EXPECT_TRUE(message_body.is_value()); + EXPECT_EQ("CAPABILITIES_RESPONSE", message_body.value()["type"].asString()); + EXPECT_EQ("error", message_body.value()["result"].asString()); +} + +TEST_F(ReceiverSessionTest, ReturnsCapabilitiesWithRemotingDefaults) { + ReceiverSession::Preferences preferences; + preferences.remoting = + std::make_unique<ReceiverSession::RemotingPreferences>(); + + SetUpWithPreferences(std::move(preferences)); + message_port_->ReceiveMessage(kGetCapabilitiesMessage); + const auto& messages = message_port_->posted_messages(); + ASSERT_EQ(1u, messages.size()); + + // We should have an error response. + auto message_body = json::Parse(messages[0]); + EXPECT_TRUE(message_body.is_value()); + EXPECT_EQ("CAPABILITIES_RESPONSE", message_body.value()["type"].asString()); + EXPECT_EQ("ok", message_body.value()["result"].asString()); + const ReceiverCapability response = + ReceiverCapability::Parse(message_body.value()["capabilities"]).value(); + + EXPECT_THAT( + response.media_capabilities, + testing::ElementsAre(MediaCapability::kOpus, MediaCapability::kAac, + MediaCapability::kVp8, MediaCapability::kH264)); +} + +TEST_F(ReceiverSessionTest, ReturnsCapabilitiesWithRemotingPreferences) { + ReceiverSession::Preferences preferences; + preferences.video_codecs = {VideoCodec::kH264}; + preferences.remoting = + std::make_unique<ReceiverSession::RemotingPreferences>(); + preferences.remoting->supports_chrome_audio_codecs = true; + preferences.remoting->supports_4k = true; + + SetUpWithPreferences(std::move(preferences)); + message_port_->ReceiveMessage(kGetCapabilitiesMessage); + const auto& messages = message_port_->posted_messages(); + ASSERT_EQ(1u, messages.size()); + + // We should have an error response. + auto message_body = json::Parse(messages[0]); + EXPECT_TRUE(message_body.is_value()); + EXPECT_EQ("CAPABILITIES_RESPONSE", message_body.value()["type"].asString()); + EXPECT_EQ("ok", message_body.value()["result"].asString()); + const ReceiverCapability response = + ReceiverCapability::Parse(message_body.value()["capabilities"]).value(); + + EXPECT_THAT( + response.media_capabilities, + testing::ElementsAre(MediaCapability::kOpus, MediaCapability::kAac, + MediaCapability::kH264, MediaCapability::kAudio, + MediaCapability::k4k)); +} + +TEST_F(ReceiverSessionTest, CanNegotiateRemoting) { + ReceiverSession::Preferences preferences; + preferences.remoting = + std::make_unique<ReceiverSession::RemotingPreferences>(); + preferences.remoting->supports_chrome_audio_codecs = true; + preferences.remoting->supports_4k = true; + SetUpWithPreferences(std::move(preferences)); + + InSequence s; + EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _)) + .WillOnce([](const ReceiverSession* session_, + ReceiverSession::RemotingNegotiation negotiation) { + const auto& cr = negotiation.receivers; + EXPECT_TRUE(cr.audio_receiver); + EXPECT_EQ(cr.audio_receiver->config().sender_ssrc, 19088747u); + EXPECT_EQ(cr.audio_receiver->config().receiver_ssrc, 19088748u); + EXPECT_EQ(cr.audio_receiver->config().channels, 2); + EXPECT_EQ(cr.audio_receiver->config().rtp_timebase, 48000); + EXPECT_EQ(cr.audio_config.codec, AudioCodec::kNotSpecified); + + EXPECT_TRUE(cr.video_receiver); + EXPECT_EQ(cr.video_receiver->config().sender_ssrc, 19088745u); + EXPECT_EQ(cr.video_receiver->config().receiver_ssrc, 19088746u); + EXPECT_EQ(cr.video_receiver->config().channels, 1); + EXPECT_EQ(cr.video_receiver->config().rtp_timebase, 90000); + EXPECT_EQ(cr.video_config.codec, VideoCodec::kNotSpecified); + }); + EXPECT_CALL(client_, + OnReceiversDestroying(session_.get(), + ReceiverSession::Client::kEndOfSession)); + + message_port_->ReceiveMessage(kValidRemotingOfferMessage); +} + +TEST_F(ReceiverSessionTest, HandlesRpcMessage) { + ReceiverSession::Preferences preferences; + preferences.remoting = + std::make_unique<ReceiverSession::RemotingPreferences>(); + preferences.remoting->supports_chrome_audio_codecs = true; + preferences.remoting->supports_4k = true; + SetUpWithPreferences(std::move(preferences)); + + message_port_->ReceiveMessage(kRpcMessage); + const auto& messages = message_port_->posted_messages(); + // Nothing should happen yet, the session doesn't have a messenger. + ASSERT_EQ(0u, messages.size()); + + // We don't need to fully test that the subscription model on the RpcMessenger + // works, but we do want to test that the ReceiverSession has properly wired + // the RpcMessenger up to the backing SessionMessenger and can properly + // handle received RPC messages. + InSequence s; + bool received_initialize_message = false; + EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _)) + .WillOnce([this, &received_initialize_message]( + const ReceiverSession* session_, + ReceiverSession::RemotingNegotiation negotiation) mutable { + negotiation.messenger->RegisterMessageReceiverCallback( + 100, [&received_initialize_message]( + std::unique_ptr<RpcMessage> message) mutable { + ASSERT_EQ(100, message->handle()); + ASSERT_EQ(RpcMessage::RPC_DS_INITIALIZE_CALLBACK, + message->proc()); + ASSERT_EQ(0, message->integer_value()); + received_initialize_message = true; + }); + + message_port_->ReceiveMessage(kRpcMessage); + }); + EXPECT_CALL(client_, + OnReceiversDestroying(session_.get(), + ReceiverSession::Client::kEndOfSession)); + + message_port_->ReceiveMessage(kValidRemotingOfferMessage); + ASSERT_TRUE(received_initialize_message); +} + +TEST_F(ReceiverSessionTest, VideoLimitsIsSupersetOf) { + ReceiverSession::VideoLimits first{}; + ReceiverSession::VideoLimits second = first; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.max_pixels_per_second += 1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.max_pixels_per_second = second.max_pixels_per_second; + + first.max_dimensions = {1921, 1090, {kDefaultFrameRate, 1}}; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + + second.max_dimensions = {1921, 1090, {kDefaultFrameRate + 1, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + second.max_dimensions = {2000, 1000, {kDefaultFrameRate, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.max_dimensions = first.max_dimensions; + + first.min_bit_rate += 1; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.min_bit_rate = second.min_bit_rate; + + first.max_bit_rate += 1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.max_bit_rate = second.max_bit_rate; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.applies_to_all_codecs = true; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.applies_to_all_codecs = true; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.codec = VideoCodec::kVp8; + second.codec = VideoCodec::kVp9; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.applies_to_all_codecs = false; + second.applies_to_all_codecs = false; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); +} + +TEST_F(ReceiverSessionTest, AudioLimitsIsSupersetOf) { + ReceiverSession::AudioLimits first{}; + ReceiverSession::AudioLimits second = first; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.max_sample_rate += 1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.max_sample_rate = second.max_sample_rate; + + first.max_channels += 1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.max_channels = second.max_channels; + + first.min_bit_rate += 1; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.min_bit_rate = second.min_bit_rate; + + first.max_bit_rate += 1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.max_bit_rate = second.max_bit_rate; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.applies_to_all_codecs = true; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.applies_to_all_codecs = true; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.codec = AudioCodec::kOpus; + second.codec = AudioCodec::kAac; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.applies_to_all_codecs = false; + second.applies_to_all_codecs = false; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); +} + +TEST_F(ReceiverSessionTest, DisplayIsSupersetOf) { + ReceiverSession::Display first; + ReceiverSession::Display second = first; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.dimensions = {1921, 1090, {kDefaultFrameRate, 1}}; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + + second.dimensions = {1921, 1090, {kDefaultFrameRate + 1, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + second.dimensions = {2000, 1000, {kDefaultFrameRate, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.dimensions = first.dimensions; + + first.can_scale_content = true; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); +} + +TEST_F(ReceiverSessionTest, RemotingPreferencesIsSupersetOf) { + ReceiverSession::RemotingPreferences first; + ReceiverSession::RemotingPreferences second = first; + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + first.supports_chrome_audio_codecs = true; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + + second.supports_4k = true; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + + second.supports_chrome_audio_codecs = true; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); +} + +TEST_F(ReceiverSessionTest, PreferencesIsSupersetOf) { + ReceiverSession::Preferences first; + ReceiverSession::Preferences second(first); + + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + + // Modified |display_description|. + first.display_description = std::make_unique<ReceiverSession::Display>(); + first.display_description->dimensions = {1920, 1080, {kDefaultFrameRate, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second = first; + + first.display_description->dimensions = {192, 1080, {kDefaultFrameRate, 1}}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + second = first; + + // Modified |remoting|. + first.remoting = std::make_unique<ReceiverSession::RemotingPreferences>(); + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second = first; + + second.remoting->supports_4k = true; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + second = first; + + // Modified |video_codecs|. + first.video_codecs = {VideoCodec::kVp8, VideoCodec::kVp9}; + second.video_codecs = {}; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.video_codecs = {VideoCodec::kHevc}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.video_codecs.emplace_back(VideoCodec::kHevc); + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first = second; + + // Modified |audio_codecs|. + first.audio_codecs = {AudioCodec::kOpus}; + second.audio_codecs = {}; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.audio_codecs = {AudioCodec::kAac}; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first.audio_codecs.emplace_back(AudioCodec::kAac); + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + first = second; + + // Modified |video_limits|. + first.video_limits.push_back({true, VideoCodec::kVp8}); + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.video_limits.front().min_bit_rate = -1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.video_limits.push_back({true, VideoCodec::kVp9}); + second.video_limits.front().min_bit_rate = -1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.video_limits.front().applies_to_all_codecs = false; + first.video_limits.push_back({false, VideoCodec::kHevc, 123}); + second.video_limits.front().applies_to_all_codecs = false; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.video_limits.front().min_bit_rate = kDefaultVideoMinBitRate; + first.video_limits.front().min_bit_rate = kDefaultVideoMinBitRate; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + second = first; + + // Modified |audio_limits|. + first.audio_limits.push_back({true, AudioCodec::kOpus}); + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.audio_limits.front().min_bit_rate = -1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); + second.audio_limits.push_back({true, AudioCodec::kAac}); + second.audio_limits.front().min_bit_rate = -1; + EXPECT_TRUE(first.IsSupersetOf(second)); + EXPECT_TRUE(second.IsSupersetOf(first)); + first.audio_limits.front().applies_to_all_codecs = false; + first.audio_limits.push_back({false, AudioCodec::kOpus, -1}); + second.audio_limits.front().applies_to_all_codecs = false; + EXPECT_FALSE(first.IsSupersetOf(second)); + EXPECT_FALSE(second.IsSupersetOf(first)); +} + } // namespace cast } // namespace openscreen |