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