diff options
author | Jordan Bayles <jophba@chromium.org> | 2020-06-05 14:14:54 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-05 23:27:56 +0000 |
commit | 3afe77d7e243959f39568a58c8bff451eea87cbd (patch) | |
tree | e6986fedf34a47d1e8946b7b18b16175311c007e /cast/streaming/receiver_session.cc | |
parent | 977bb0c2f35a96500ecbd09b236ab39b6ddc55fd (diff) | |
download | openscreen-3afe77d7e243959f39568a58c8bff451eea87cbd.tar.gz |
Implement Answer parsing
This patch adds Answer parsing and testing, similar to how Offer
messages are currently parsed. As part of this work, the following
improvements are also included:
1. To avoid Abseil usage in public APIs, a new Optional type with
unit tests is included.
2. message_util.h helpers have been greatly expanded, moved to
util/json/parsing_helpers.h, and unit tests added.
3. SimpleFraction has been moved from util/ to platform/base/, so it can
be properly used in public APIs.
4. SessionConfig has been cleaned up to follow coding style guidelines.
5. ANSWER message creation (that encapsulates the Answer struct) has
been moved to the ReceiverSession.
Bug: b/152633271, b/158030843
Change-Id: I59c20a140a5174d45378fb9b647ccbe5e6d23d1b
Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/2219571
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Reviewed-by: mark a. foltz <mfoltz@chromium.org>
Reviewed-by: Ryan Keane <rwkeane@google.com>
Diffstat (limited to 'cast/streaming/receiver_session.cc')
-rw-r--r-- | cast/streaming/receiver_session.cc | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/cast/streaming/receiver_session.cc b/cast/streaming/receiver_session.cc index 5d2e74bd..467fd27d 100644 --- a/cast/streaming/receiver_session.cc +++ b/cast/streaming/receiver_session.cc @@ -12,14 +12,15 @@ #include "absl/strings/numbers.h" #include "cast/streaming/environment.h" #include "cast/streaming/message_port.h" -#include "cast/streaming/message_util.h" #include "cast/streaming/offer_messages.h" #include "cast/streaming/receiver.h" +#include "util/json/json_helpers.h" #include "util/osp_logging.h" namespace openscreen { namespace cast { +/// NOTE: Constants here are all taken from the Cast V2: Mirroring Control // JSON message field values specific to the Receiver Session. static constexpr char kMessageTypeOffer[] = "OFFER"; @@ -28,6 +29,20 @@ static constexpr char kOfferMessageBody[] = "offer"; static constexpr char kKeyType[] = "type"; static constexpr char kSequenceNumber[] = "seqNum"; +/// Protocol specification: http://goto.google.com/mirroring-control-protocol +// TODO(jophba): document the protocol in a public repository. +static constexpr char kMessageKeyType[] = "type"; +static constexpr char kMessageTypeAnswer[] = "ANSWER"; + +/// ANSWER message fields. +static constexpr char kAnswerMessageBody[] = "answer"; +static constexpr char kResult[] = "result"; +static constexpr char kResultOk[] = "ok"; +static constexpr char kResultError[] = "error"; +static constexpr char kErrorMessageBody[] = "error"; +static constexpr char kErrorCode[] = "code"; +static constexpr char kErrorDescription[] = "description"; + // Using statements for constructor readability. using Preferences = ReceiverSession::Preferences; using ConfiguredReceivers = ReceiverSession::ConfiguredReceivers; @@ -76,7 +91,30 @@ const Stream* SelectStream(const std::vector<Codec>& preferred_codecs, } return nullptr; } +// Helper method that creates an invalid Answer response. +Json::Value CreateInvalidAnswerMessage(Error error) { + Json::Value message_root; + message_root[kMessageKeyType] = kMessageTypeAnswer; + message_root[kResult] = kResultError; + message_root[kErrorMessageBody][kErrorCode] = static_cast<int>(error.code()); + message_root[kErrorMessageBody][kErrorDescription] = error.message(); + + return message_root; +} +// Helper method that creates an Answer response. May be valid or invalid. +Json::Value CreateAnswerMessage(const Answer& answer) { + if (!answer.IsValid()) { + return CreateInvalidAnswerMessage(Error(Error::Code::kParameterInvalid, + "Answer struct in invalid state")); + } + + Json::Value message_root; + message_root[kMessageKeyType] = kMessageTypeAnswer; + message_root[kAnswerMessageBody] = answer.ToJson(); + message_root[kResult] = kResultOk; + return message_root; +} } // namespace Preferences::Preferences() = default; @@ -129,21 +167,22 @@ void ReceiverSession::OnMessage(absl::string_view sender_id, } // TODO(jophba): add sender connected/disconnected messaging. - auto sequence_number = ParseInt(message_json.value(), kSequenceNumber); - if (!sequence_number) { + int sequence_number; + if (!json::ParseAndValidateInt(message_json.value()[kSequenceNumber], + &sequence_number)) { OSP_LOG_WARN << "Invalid message sequence number"; return; } - auto key_or_error = ParseString(message_json.value(), kKeyType); - if (!key_or_error) { + std::string key; + if (!json::ParseAndValidateString(message_json.value()[kKeyType], &key)) { OSP_LOG_WARN << "Invalid message key"; return; } Message parsed_message{sender_id.data(), message_namespace.data(), - sequence_number.value()}; - if (key_or_error.value() == kMessageTypeOffer) { + sequence_number}; + if (key == kMessageTypeOffer) { parsed_message.body = std::move(message_json.value()[kOfferMessageBody]); if (parsed_message.body.isNull()) { OSP_LOG_WARN << "Invalid message offer body"; @@ -180,7 +219,6 @@ void ReceiverSession::OnOffer(Message* message) { SelectStream(preferences_.video_codecs, offer.value().video_streams); } - cast_mode_ = offer.value().cast_mode; auto receivers = TrySpawningReceivers(selected_audio_stream, selected_video_stream); if (receivers) { @@ -188,9 +226,9 @@ void ReceiverSession::OnOffer(Message* message) { ConstructAnswer(message, selected_audio_stream, selected_video_stream); client_->OnNegotiated(this, std::move(receivers.value())); - message->body = answer.ToAnswerMessage(); + message->body = CreateAnswerMessage(answer); } else { - message->body = CreateInvalidAnswer(receivers.error()); + message->body = CreateInvalidAnswerMessage(receivers.error()); } SendMessage(message); @@ -266,20 +304,20 @@ Answer ReceiverSession::ConstructAnswer( absl::optional<Constraints> constraints; if (preferences_.constraints) { - constraints = *preferences_.constraints; + constraints = absl::optional<Constraints>(*preferences_.constraints); } absl::optional<DisplayDescription> display; if (preferences_.display_description) { - display = *preferences_.display_description; + display = + absl::optional<DisplayDescription>(*preferences_.display_description); } - return Answer{cast_mode_, - environment_->GetBoundLocalEndpoint().port, + return Answer{environment_->GetBoundLocalEndpoint().port, std::move(stream_indexes), std::move(stream_ssrcs), - constraints, - display, + std::move(constraints), + std::move(display), std::vector<int>{}, // receiver_rtcp_event_log std::vector<int>{}, // receiver_rtcp_dscp supports_wifi_status_reporting_}; |