• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cast/streaming/receiver_message.h"
6 
7 #include <utility>
8 
9 #include "absl/strings/ascii.h"
10 #include "absl/types/optional.h"
11 #include "cast/streaming/message_fields.h"
12 #include "json/reader.h"
13 #include "json/writer.h"
14 #include "platform/base/error.h"
15 #include "util/base64.h"
16 #include "util/enum_name_table.h"
17 #include "util/json/json_helpers.h"
18 #include "util/json/json_serialization.h"
19 
20 namespace openscreen {
21 namespace cast {
22 
23 namespace {
24 
25 EnumNameTable<ReceiverMessage::Type, 5> kMessageTypeNames{
26     {{kMessageTypeAnswer, ReceiverMessage::Type::kAnswer},
27      {"CAPABILITIES_RESPONSE", ReceiverMessage::Type::kCapabilitiesResponse},
28      {"RPC", ReceiverMessage::Type::kRpc}}};
29 
30 EnumNameTable<MediaCapability, 10> kMediaCapabilityNames{
31     {{"audio", MediaCapability::kAudio},
32      {"aac", MediaCapability::kAac},
33      {"opus", MediaCapability::kOpus},
34      {"video", MediaCapability::kVideo},
35      {"4k", MediaCapability::k4k},
36      {"h264", MediaCapability::kH264},
37      {"vp8", MediaCapability::kVp8},
38      {"vp9", MediaCapability::kVp9},
39      {"hevc", MediaCapability::kHevc},
40      {"av1", MediaCapability::kAv1}}};
41 
GetMessageType(const Json::Value & root)42 ReceiverMessage::Type GetMessageType(const Json::Value& root) {
43   std::string type;
44   if (!json::TryParseString(root[kMessageType], &type)) {
45     return ReceiverMessage::Type::kUnknown;
46   }
47 
48   absl::AsciiStrToUpper(&type);
49   ErrorOr<ReceiverMessage::Type> parsed = GetEnum(kMessageTypeNames, type);
50 
51   return parsed.value(ReceiverMessage::Type::kUnknown);
52 }
53 
TryParseCapability(const Json::Value & value,MediaCapability * out)54 bool TryParseCapability(const Json::Value& value, MediaCapability* out) {
55   std::string c;
56   if (!json::TryParseString(value, &c)) {
57     return false;
58   }
59 
60   const ErrorOr<MediaCapability> capability = GetEnum(kMediaCapabilityNames, c);
61   if (capability.is_error()) {
62     return false;
63   }
64 
65   *out = capability.value();
66   return true;
67 }
68 
69 }  // namespace
70 
71 // static
Parse(const Json::Value & value)72 ErrorOr<ReceiverError> ReceiverError::Parse(const Json::Value& value) {
73   if (!value) {
74     return Error(Error::Code::kParameterInvalid,
75                  "Empty JSON in receiver error parsing");
76   }
77 
78   int code;
79   std::string description;
80   if (!json::TryParseInt(value[kErrorCode], &code) ||
81       !json::TryParseString(value[kErrorDescription], &description)) {
82     return Error::Code::kJsonParseError;
83   }
84   return ReceiverError{code, description};
85 }
86 
ToJson() const87 Json::Value ReceiverError::ToJson() const {
88   Json::Value root;
89   root[kErrorCode] = code;
90   root[kErrorDescription] = description;
91   return root;
92 }
93 
94 // static
Parse(const Json::Value & value)95 ErrorOr<ReceiverCapability> ReceiverCapability::Parse(
96     const Json::Value& value) {
97   if (!value) {
98     return Error(Error::Code::kParameterInvalid,
99                  "Empty JSON in capabilities parsing");
100   }
101 
102   int remoting_version;
103   if (!json::TryParseInt(value["remoting"], &remoting_version)) {
104     remoting_version = ReceiverCapability::kRemotingVersionUnknown;
105   }
106 
107   std::vector<MediaCapability> capabilities;
108   if (!json::TryParseArray<MediaCapability>(
109           value["mediaCaps"], TryParseCapability, &capabilities)) {
110     return Error(Error::Code::kJsonParseError,
111                  "Failed to parse media capabilities");
112   }
113 
114   return ReceiverCapability{remoting_version, std::move(capabilities)};
115 }
116 
ToJson() const117 Json::Value ReceiverCapability::ToJson() const {
118   Json::Value root;
119   root["remoting"] = remoting_version;
120   Json::Value capabilities(Json::ValueType::arrayValue);
121   for (const auto& capability : media_capabilities) {
122     capabilities.append(GetEnumName(kMediaCapabilityNames, capability).value());
123   }
124   root["mediaCaps"] = std::move(capabilities);
125   return root;
126 }
127 
128 // static
Parse(const Json::Value & value)129 ErrorOr<ReceiverMessage> ReceiverMessage::Parse(const Json::Value& value) {
130   ReceiverMessage message;
131   if (!value) {
132     return Error(Error::Code::kJsonParseError, "Invalid message body");
133   }
134 
135   std::string result;
136   if (!json::TryParseString(value[kResult], &result)) {
137     result = kResultError;
138   }
139 
140   message.type = GetMessageType(value);
141   message.valid =
142       (result == kResultOk || message.type == ReceiverMessage::Type::kRpc);
143   if (!message.valid) {
144     ErrorOr<ReceiverError> error =
145         ReceiverError::Parse(value[kErrorMessageBody]);
146     if (error.is_value()) {
147       message.body = std::move(error.value());
148     }
149     return message;
150   }
151 
152   switch (message.type) {
153     case Type::kAnswer: {
154       Answer answer;
155       if (openscreen::cast::Answer::TryParse(value[kAnswerMessageBody],
156                                              &answer)) {
157         message.body = std::move(answer);
158         message.valid = true;
159       }
160     } break;
161 
162     case Type::kCapabilitiesResponse: {
163       ErrorOr<ReceiverCapability> capability =
164           ReceiverCapability::Parse(value[kCapabilitiesMessageBody]);
165       if (capability.is_value()) {
166         message.body = std::move(capability.value());
167         message.valid = true;
168       }
169     } break;
170 
171     case Type::kRpc: {
172       std::string encoded_rpc;
173       std::vector<uint8_t> rpc;
174       if (json::TryParseString(value[kRpcMessageBody], &encoded_rpc) &&
175           base64::Decode(encoded_rpc, &rpc)) {
176         message.body = std::move(rpc);
177         message.valid = true;
178       }
179     } break;
180 
181     default:
182       break;
183   }
184 
185   if (message.type != ReceiverMessage::Type::kRpc &&
186       !json::TryParseInt(value[kSequenceNumber], &(message.sequence_number))) {
187     message.sequence_number = -1;
188     message.valid = false;
189   }
190 
191   return message;
192 }
193 
ToJson() const194 ErrorOr<Json::Value> ReceiverMessage::ToJson() const {
195   OSP_CHECK(type != ReceiverMessage::Type::kUnknown)
196       << "Trying to send an unknown message is a developer error";
197 
198   Json::Value root;
199   root[kMessageType] = GetEnumName(kMessageTypeNames, type).value();
200   if (sequence_number >= 0) {
201     root[kSequenceNumber] = sequence_number;
202   }
203 
204   switch (type) {
205     case ReceiverMessage::Type::kAnswer:
206       if (valid) {
207         root[kResult] = kResultOk;
208         root[kAnswerMessageBody] = absl::get<Answer>(body).ToJson();
209       } else {
210         root[kResult] = kResultError;
211         root[kErrorMessageBody] = absl::get<ReceiverError>(body).ToJson();
212       }
213       break;
214 
215     case ReceiverMessage::Type::kCapabilitiesResponse:
216       if (valid) {
217         root[kResult] = kResultOk;
218         root[kCapabilitiesMessageBody] =
219             absl::get<ReceiverCapability>(body).ToJson();
220       } else {
221         root[kResult] = kResultError;
222         root[kErrorMessageBody] = absl::get<ReceiverError>(body).ToJson();
223       }
224       break;
225 
226     // NOTE: RPC messages do NOT have a result field.
227     case ReceiverMessage::Type::kRpc:
228       root[kRpcMessageBody] =
229           base64::Encode(absl::get<std::vector<uint8_t>>(body));
230       break;
231 
232     default:
233       OSP_NOTREACHED();
234   }
235 
236   return root;
237 }
238 
239 }  // namespace cast
240 }  // namespace openscreen
241