Upload upstream chromium 73.0.3683.0
[platform/framework/web/chromium-efl.git] / components / cast_channel / cast_message_util.cc
1 // Copyright 2014 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 "components/cast_channel/cast_message_util.h"
6
7 #include <memory>
8
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "build/build_config.h"
14 #include "components/cast_channel/cast_auth_util.h"
15 #include "components/cast_channel/proto/cast_channel.pb.h"
16
17 using base::Value;
18
19 namespace cast_channel {
20
21 namespace {
22
23 // String values for CastMessageType enum.
24 constexpr char kCastMessageTypePingString[] = "PING";
25 constexpr char kCastMessageTypePongString[] = "PONG";
26 constexpr char kCastMessageTypeGetAppAvailabilityString[] =
27     "GET_APP_AVAILABILITY";
28 constexpr char kCastMessageTypeReceiverStatusRequestString[] = "GET_STATUS";
29 constexpr char kCastMessageTypeConnectString[] = "CONNECT";
30 constexpr char kCastMessageTypeCloseConnectionString[] = "CLOSE";
31 constexpr char kCastMessageTypeBroadcastString[] = "APPLICATION_BROADCAST";
32 constexpr char kCastMessageTypeLaunchString[] = "LAUNCH";
33 constexpr char kCastMessageTypeStopString[] = "STOP";
34 constexpr char kCastMessageTypeReceiverStatusString[] = "RECEIVER_STATUS";
35 constexpr char kCastMessageTypeMediaStatusString[] = "MEDIA_STATUS";
36 constexpr char kCastMessageTypeLaunchErrorString[] = "LAUNCH_ERROR";
37
38 // String values for V2MessageType enum.
39 constexpr char kV2MessageTypeEditTracksInfoString[] = "EDIT_TRACKS_INFO";
40 constexpr char kV2MessageTypeGetStatusString[] = "GET_STATUS";
41 constexpr char kV2MessageTypeLoadString[] = "LOAD";
42 constexpr char kV2MessageTypeMediaGetStatusString[] = "MEDIA_GET_STATUS";
43 constexpr char kV2MessageTypeMediaSetVolumeString[] = "MEDIA_SET_VOLUME";
44 constexpr char kV2MessageTypePauseString[] = "PAUSE";
45 constexpr char kV2MessageTypePlayString[] = "PLAY";
46 constexpr char kV2MessageTypePrecacheString[] = "PRECACHE";
47 constexpr char kV2MessageTypeQueueInsertString[] = "QUEUE_INSERT";
48 constexpr char kV2MessageTypeQueueLoadString[] = "QUEUE_LOAD";
49 constexpr char kV2MessageTypeQueueRemoveString[] = "QUEUE_REMOVE";
50 constexpr char kV2MessageTypeQueueReorderString[] = "QUEUE_REORDER";
51 constexpr char kV2MessageTypeQueueUpdateString[] = "QUEUE_UPDATE";
52 constexpr char kV2MessageTypeSeekString[] = "SEEK";
53 constexpr char kV2MessageTypeSetVolumeString[] = "SET_VOLUME";
54 constexpr char kV2MessageTypeStopString[] = "STOP";
55 constexpr char kV2MessageTypeStopMediaString[] = "STOP_MEDIA";
56
57 // String values for GetAppAvailabilityResult enum.
58 constexpr char kGetAppAvailabilityResultAvailableString[] = "APP_AVAILABLE";
59 constexpr char kGetAppAvailabilityResultUnavailableString[] = "APP_UNAVAILABLE";
60
61 // The value used for "sdkType" in a virtual connect request. Historically, this
62 // value is used in the Media Router extension, but here it is reused in Chrome.
63 constexpr int kVirtualConnectSdkType = 2;
64
65 // The value used for "connectionType" in a virtual connect request. This value
66 // stands for CONNECTION_TYPE_LOCAL, which is the only type used in Chrome.
67 constexpr int kVirtualConnectTypeLocal = 1;
68
69 void FillCommonCastMessageFields(CastMessage* message,
70                                  const std::string& source_id,
71                                  const std::string& destination_id,
72                                  const std::string& message_namespace) {
73   message->set_protocol_version(CastMessage::CASTV2_1_0);
74   message->set_source_id(source_id);
75   message->set_destination_id(destination_id);
76   message->set_namespace_(message_namespace);
77 }
78
79 CastMessage CreateKeepAliveMessage(base::StringPiece keep_alive_type) {
80   base::Value type_dict(base::Value::Type::DICTIONARY);
81   type_dict.SetKey("type", base::Value(keep_alive_type));
82   return CreateCastMessage(kHeartbeatNamespace, type_dict, kPlatformSenderId,
83                            kPlatformReceiverId);
84 }
85
86 // Returns the value to be set as the "platform" value in a virtual connect
87 // request. The value is platform-dependent and is taken from the Platform enum
88 // defined in third_party/metrics_proto/cast_logs.proto.
89 int GetVirtualConnectPlatformValue() {
90 #if defined(OS_WIN)
91   return 3;
92 #elif defined(OS_MACOSX)
93   return 4;
94 #elif defined(OS_CHROMEOS)
95   return 5;
96 #elif defined(OS_LINUX)
97   return 6;
98 #else
99   return 0;
100 #endif
101 }
102
103 // Maps from from API-internal message types to "real" message types from the
104 // Cast V2 protocol.  This is necessary because the protocol defines messages
105 // with the same type in different namespaces, and the namespace is lost when
106 // messages are passed using a CastInternalMessage object.
107 std::string GetRemappedMediaRequestType(const std::string& v2_message_type) {
108   V2MessageType type = V2MessageTypeFromString(v2_message_type);
109   DCHECK(IsMediaRequestMessageType(type));
110   const char* result;
111   switch (type) {
112     case V2MessageType::kStopMedia:
113       result = ToString(V2MessageType::kStop);
114       break;
115     case V2MessageType::kMediaSetVolume:
116       result = ToString(V2MessageType::kSetVolume);
117       break;
118     case V2MessageType::kMediaGetStatus:
119       result = ToString(V2MessageType::kGetStatus);
120       break;
121     default:
122       return v2_message_type;
123   }
124   DCHECK(result);
125   return result;
126 }
127
128 }  // namespace
129
130 bool IsCastMessageValid(const CastMessage& message_proto) {
131   if (!message_proto.IsInitialized())
132     return false;
133
134   if (message_proto.namespace_().empty() || message_proto.source_id().empty() ||
135       message_proto.destination_id().empty()) {
136     return false;
137   }
138   return (message_proto.payload_type() == CastMessage_PayloadType_STRING &&
139           message_proto.has_payload_utf8()) ||
140          (message_proto.payload_type() == CastMessage_PayloadType_BINARY &&
141           message_proto.has_payload_binary());
142 }
143
144 bool IsCastInternalNamespace(const std::string& message_namespace) {
145   // Note: any namespace with the prefix is assumed to be reserved for internal
146   // messages.
147   return base::StartsWith(message_namespace, kCastInternalNamespacePrefix,
148                           base::CompareCase::SENSITIVE);
149 }
150
151 CastMessageType ParseMessageTypeFromPayload(const base::Value& payload) {
152   const Value* type_string = payload.FindKeyOfType("type", Value::Type::STRING);
153   return type_string ? CastMessageTypeFromString(type_string->GetString())
154                      : CastMessageType::kOther;
155 }
156
157 const char* ToString(CastMessageType message_type) {
158   switch (message_type) {
159     case CastMessageType::kPing:
160       return kCastMessageTypePingString;
161     case CastMessageType::kPong:
162       return kCastMessageTypePongString;
163     case CastMessageType::kGetAppAvailability:
164       return kCastMessageTypeGetAppAvailabilityString;
165     case CastMessageType::kReceiverStatusRequest:
166       return kCastMessageTypeReceiverStatusRequestString;
167     case CastMessageType::kConnect:
168       return kCastMessageTypeConnectString;
169     case CastMessageType::kCloseConnection:
170       return kCastMessageTypeCloseConnectionString;
171     case CastMessageType::kBroadcast:
172       return kCastMessageTypeBroadcastString;
173     case CastMessageType::kLaunch:
174       return kCastMessageTypeLaunchString;
175     case CastMessageType::kStop:
176       return kCastMessageTypeStopString;
177     case CastMessageType::kReceiverStatus:
178       return kCastMessageTypeReceiverStatusString;
179     case CastMessageType::kMediaStatus:
180       return kCastMessageTypeMediaStatusString;
181     case CastMessageType::kLaunchError:
182       return kCastMessageTypeLaunchErrorString;
183     default:
184       return "";
185   }
186 }
187
188 const char* ToString(V2MessageType message_type) {
189   switch (message_type) {
190     case V2MessageType::kEditTracksInfo:
191       return kV2MessageTypeEditTracksInfoString;
192     case V2MessageType::kGetStatus:
193       return kV2MessageTypeGetStatusString;
194     case V2MessageType::kLoad:
195       return kV2MessageTypeLoadString;
196     case V2MessageType::kMediaGetStatus:
197       return kV2MessageTypeMediaGetStatusString;
198     case V2MessageType::kMediaSetVolume:
199       return kV2MessageTypeMediaSetVolumeString;
200     case V2MessageType::kPause:
201       return kV2MessageTypePauseString;
202     case V2MessageType::kPlay:
203       return kV2MessageTypePlayString;
204     case V2MessageType::kPrecache:
205       return kV2MessageTypePrecacheString;
206     case V2MessageType::kQueueInsert:
207       return kV2MessageTypeQueueInsertString;
208     case V2MessageType::kQueueLoad:
209       return kV2MessageTypeQueueLoadString;
210     case V2MessageType::kQueueRemove:
211       return kV2MessageTypeQueueRemoveString;
212     case V2MessageType::kQueueReorder:
213       return kV2MessageTypeQueueReorderString;
214     case V2MessageType::kQueueUpdate:
215       return kV2MessageTypeQueueUpdateString;
216     case V2MessageType::kSeek:
217       return kV2MessageTypeSeekString;
218     case V2MessageType::kSetVolume:
219       return kV2MessageTypeSetVolumeString;
220     case V2MessageType::kStop:
221       return kV2MessageTypeStopString;
222     case V2MessageType::kStopMedia:
223       return kV2MessageTypeStopMediaString;
224     default:
225       return nullptr;
226   }
227 }
228
229 CastMessageType CastMessageTypeFromString(const std::string& type) {
230   if (type == kCastMessageTypePingString)
231     return CastMessageType::kPing;
232   if (type == kCastMessageTypePongString)
233     return CastMessageType::kPong;
234   if (type == kCastMessageTypeGetAppAvailabilityString)
235     return CastMessageType::kGetAppAvailability;
236   if (type == kCastMessageTypeReceiverStatusRequestString)
237     return CastMessageType::kReceiverStatusRequest;
238   if (type == kCastMessageTypeConnectString)
239     return CastMessageType::kConnect;
240   if (type == kCastMessageTypeCloseConnectionString)
241     return CastMessageType::kCloseConnection;
242   if (type == kCastMessageTypeBroadcastString)
243     return CastMessageType::kBroadcast;
244   if (type == kCastMessageTypeLaunchString)
245     return CastMessageType::kLaunch;
246   if (type == kCastMessageTypeStopString)
247     return CastMessageType::kStop;
248   if (type == kCastMessageTypeReceiverStatusString)
249     return CastMessageType::kReceiverStatus;
250   if (type == kCastMessageTypeMediaStatusString)
251     return CastMessageType::kMediaStatus;
252   if (type == kCastMessageTypeLaunchErrorString)
253     return CastMessageType::kLaunchError;
254   DVLOG(1) << "Unknown message type: " << type;
255   return CastMessageType::kOther;
256 }
257
258 V2MessageType V2MessageTypeFromString(const std::string& type) {
259   if (type == kV2MessageTypeGetStatusString)
260     return V2MessageType::kGetStatus;
261   if (type == kV2MessageTypeLoadString)
262     return V2MessageType::kLoad;
263   if (type == kV2MessageTypeMediaGetStatusString)
264     return V2MessageType::kMediaGetStatus;
265   if (type == kV2MessageTypeMediaSetVolumeString)
266     return V2MessageType::kMediaSetVolume;
267   if (type == kV2MessageTypePauseString)
268     return V2MessageType::kPause;
269   if (type == kV2MessageTypePlayString)
270     return V2MessageType::kPlay;
271   if (type == kV2MessageTypePrecacheString)
272     return V2MessageType::kPrecache;
273   if (type == kV2MessageTypeQueueInsertString)
274     return V2MessageType::kQueueInsert;
275   if (type == kV2MessageTypeQueueLoadString)
276     return V2MessageType::kQueueLoad;
277   if (type == kV2MessageTypeQueueRemoveString)
278     return V2MessageType::kQueueRemove;
279   if (type == kV2MessageTypeQueueReorderString)
280     return V2MessageType::kQueueReorder;
281   if (type == kV2MessageTypeQueueUpdateString)
282     return V2MessageType::kQueueUpdate;
283   if (type == kV2MessageTypeSeekString)
284     return V2MessageType::kSeek;
285   if (type == kV2MessageTypeSetVolumeString)
286     return V2MessageType::kSetVolume;
287   if (type == kV2MessageTypeStopString)
288     return V2MessageType::kStop;
289   if (type == kV2MessageTypeStopMediaString)
290     return V2MessageType::kStopMedia;
291   else
292     return V2MessageType::kOther;
293 }
294
295 std::string CastMessageToString(const CastMessage& message_proto) {
296   std::string out("{");
297   out += "namespace = " + message_proto.namespace_();
298   out += ", sourceId = " + message_proto.source_id();
299   out += ", destId = " + message_proto.destination_id();
300   out += ", type = " + base::IntToString(message_proto.payload_type());
301   out += ", str = \"" + message_proto.payload_utf8() + "\"}";
302   return out;
303 }
304
305 std::string AuthMessageToString(const DeviceAuthMessage& message) {
306   std::string out("{");
307   if (message.has_challenge()) {
308     out += "challenge: {}, ";
309   }
310   if (message.has_response()) {
311     out += "response: {signature: (";
312     out += base::NumberToString(message.response().signature().length());
313     out += " bytes), certificate: (";
314     out += base::NumberToString(
315         message.response().client_auth_certificate().length());
316     out += " bytes)}";
317   }
318   if (message.has_error()) {
319     out += ", error: {";
320     out += base::IntToString(message.error().error_type());
321     out += "}";
322   }
323   out += "}";
324   return out;
325 }
326
327 void CreateAuthChallengeMessage(CastMessage* message_proto,
328                                 const AuthContext& auth_context) {
329   CHECK(message_proto);
330   DeviceAuthMessage auth_message;
331
332   AuthChallenge* challenge = auth_message.mutable_challenge();
333   DCHECK(challenge);
334   challenge->set_sender_nonce(auth_context.nonce());
335   challenge->set_hash_algorithm(SHA256);
336
337   std::string auth_message_string;
338   auth_message.SerializeToString(&auth_message_string);
339
340   FillCommonCastMessageFields(message_proto, kPlatformSenderId,
341                               kPlatformReceiverId, kAuthNamespace);
342   message_proto->set_payload_type(CastMessage_PayloadType_BINARY);
343   message_proto->set_payload_binary(auth_message_string);
344 }
345
346 bool IsAuthMessage(const CastMessage& message) {
347   return message.namespace_() == kAuthNamespace;
348 }
349
350 bool IsReceiverMessage(const CastMessage& message) {
351   return message.namespace_() == kReceiverNamespace;
352 }
353
354 bool IsPlatformSenderMessage(const CastMessage& message) {
355   return message.destination_id() != cast_channel::kPlatformSenderId;
356 }
357
358 CastMessage CreateKeepAlivePingMessage() {
359   return CreateKeepAliveMessage(kCastMessageTypePingString);
360 }
361
362 CastMessage CreateKeepAlivePongMessage() {
363   return CreateKeepAliveMessage(kCastMessageTypePongString);
364 }
365
366 CastMessage CreateVirtualConnectionRequest(
367     const std::string& source_id,
368     const std::string& destination_id,
369     VirtualConnectionType connection_type,
370     const std::string& user_agent,
371     const std::string& browser_version) {
372   DCHECK(destination_id != kPlatformReceiverId || connection_type == kStrong);
373
374   // Parse system_version from user agent string. It contains platform, OS and
375   // CPU info and is contained in the first set of parentheses of the user
376   // agent string (e.g., X11; Linux x86_64).
377   std::string system_version;
378   size_t start_index = user_agent.find('(');
379   if (start_index != std::string::npos) {
380     size_t end_index = user_agent.find(')', start_index + 1);
381     if (end_index != std::string::npos) {
382       system_version =
383           user_agent.substr(start_index + 1, end_index - start_index - 1);
384     }
385   }
386
387   Value dict(Value::Type::DICTIONARY);
388   dict.SetKey("type", Value(kCastMessageTypeConnectString));
389   dict.SetKey("userAgent", Value(user_agent));
390   dict.SetKey("connType", Value(connection_type));
391   dict.SetKey("origin", Value(Value::Type::DICTIONARY));
392
393   Value sender_info(Value::Type::DICTIONARY);
394   sender_info.SetKey("sdkType", Value(kVirtualConnectSdkType));
395   sender_info.SetKey("version", Value(browser_version));
396   sender_info.SetKey("browserVersion", Value(browser_version));
397   sender_info.SetKey("platform", Value(GetVirtualConnectPlatformValue()));
398   sender_info.SetKey("connectionType", Value(kVirtualConnectTypeLocal));
399   if (!system_version.empty())
400     sender_info.SetKey("systemVersion", Value(system_version));
401
402   dict.SetKey("senderInfo", std::move(sender_info));
403
404   return CreateCastMessage(kConnectionNamespace, dict, source_id,
405                            destination_id);
406 }
407
408 CastMessage CreateGetAppAvailabilityRequest(const std::string& source_id,
409                                             int request_id,
410                                             const std::string& app_id) {
411   Value dict(Value::Type::DICTIONARY);
412   dict.SetKey("type", Value(kCastMessageTypeGetAppAvailabilityString));
413   Value app_id_value(Value::Type::LIST);
414   app_id_value.GetList().push_back(Value(app_id));
415   dict.SetKey("appId", std::move(app_id_value));
416   dict.SetKey("requestId", Value(request_id));
417
418   return CreateCastMessage(kReceiverNamespace, dict, source_id,
419                            kPlatformReceiverId);
420 }
421
422 CastMessage CreateReceiverStatusRequest(const std::string& source_id,
423                                         int request_id) {
424   Value dict(Value::Type::DICTIONARY);
425   dict.SetKey("type", Value(kCastMessageTypeReceiverStatusRequestString));
426   dict.SetKey("requestId", Value(request_id));
427   return CreateCastMessage(kReceiverNamespace, dict, source_id,
428                            kPlatformReceiverId);
429 }
430
431 BroadcastRequest::BroadcastRequest(const std::string& broadcast_namespace,
432                                    const std::string& message)
433     : broadcast_namespace(broadcast_namespace), message(message) {}
434 BroadcastRequest::~BroadcastRequest() = default;
435
436 bool BroadcastRequest::operator==(const BroadcastRequest& other) const {
437   return broadcast_namespace == other.broadcast_namespace &&
438          message == other.message;
439 }
440
441 CastMessage CreateBroadcastRequest(const std::string& source_id,
442                                    int request_id,
443                                    const std::vector<std::string>& app_ids,
444                                    const BroadcastRequest& request) {
445   Value dict(Value::Type::DICTIONARY);
446   dict.SetKey("type", Value(kCastMessageTypeBroadcastString));
447   std::vector<Value> app_ids_value;
448   for (const std::string& app_id : app_ids)
449     app_ids_value.push_back(Value(app_id));
450
451   dict.SetKey("appIds", Value(std::move(app_ids_value)));
452   dict.SetKey("namespace", Value(request.broadcast_namespace));
453   dict.SetKey("message", Value(request.message));
454   return CreateCastMessage(kBroadcastNamespace, dict, source_id,
455                            kPlatformReceiverId);
456 }
457
458 CastMessage CreateLaunchRequest(const std::string& source_id,
459                                 int request_id,
460                                 const std::string& app_id,
461                                 const std::string& locale) {
462   Value dict(Value::Type::DICTIONARY);
463   dict.SetKey("type", Value(kCastMessageTypeLaunchString));
464   dict.SetKey("requestId", Value(request_id));
465   dict.SetKey("appId", Value(app_id));
466   dict.SetKey("language", Value(locale));
467
468   return CreateCastMessage(kReceiverNamespace, dict, source_id,
469                            kPlatformReceiverId);
470 }
471
472 CastMessage CreateStopRequest(const std::string& source_id,
473                               int request_id,
474                               const std::string& session_id) {
475   Value dict(Value::Type::DICTIONARY);
476   dict.SetKey("type", Value(kCastMessageTypeStopString));
477   dict.SetKey("requestId", Value(request_id));
478   dict.SetKey("sessionId", Value(session_id));
479   return CreateCastMessage(kReceiverNamespace, dict, source_id,
480                            kPlatformReceiverId);
481 }
482
483 CastMessage CreateCastMessage(const std::string& message_namespace,
484                               const base::Value& message,
485                               const std::string& source_id,
486                               const std::string& destination_id) {
487   CastMessage output;
488   FillCommonCastMessageFields(&output, source_id, destination_id,
489                               message_namespace);
490   output.set_payload_type(
491       CastMessage::PayloadType::CastMessage_PayloadType_STRING);
492   CHECK(base::JSONWriter::Write(message, output.mutable_payload_utf8()));
493   return output;
494 }
495
496 CastMessage CreateMediaRequest(const base::Value& body,
497                                int request_id,
498                                const std::string& source_id,
499                                const std::string& destination_id) {
500   Value dict = body.Clone();
501   Value* type = dict.FindKeyOfType("type", Value::Type::STRING);
502   CHECK(type);
503   dict.SetKey("type", Value(GetRemappedMediaRequestType(type->GetString())));
504   dict.SetKey("requestId", Value(request_id));
505   return CreateCastMessage(kMediaNamespace, dict, source_id, destination_id);
506 }
507
508 CastMessage CreateSetVolumeRequest(const base::Value& body,
509                                    int request_id,
510                                    const std::string& source_id) {
511   DCHECK(body.FindKeyOfType("type", Value::Type::STRING) &&
512          body.FindKeyOfType("type", Value::Type::STRING)->GetString() ==
513              kV2MessageTypeSetVolumeString);
514   Value dict = body.Clone();
515   dict.RemoveKey("sessionId");
516   dict.SetKey("requestId", Value(request_id));
517   return CreateCastMessage(kReceiverNamespace, dict, source_id,
518                            kPlatformReceiverId);
519 }
520
521 bool IsMediaRequestMessageType(V2MessageType type) {
522   switch (type) {
523     case V2MessageType::kEditTracksInfo:
524     case V2MessageType::kLoad:
525     case V2MessageType::kMediaGetStatus:
526     case V2MessageType::kMediaSetVolume:
527     case V2MessageType::kPause:
528     case V2MessageType::kPlay:
529     case V2MessageType::kPrecache:
530     case V2MessageType::kQueueInsert:
531     case V2MessageType::kQueueLoad:
532     case V2MessageType::kQueueRemove:
533     case V2MessageType::kQueueReorder:
534     case V2MessageType::kQueueUpdate:
535     case V2MessageType::kSeek:
536     case V2MessageType::kStopMedia:
537       return true;
538     default:
539       return false;
540   }
541 }
542
543 const char* ToString(GetAppAvailabilityResult result) {
544   switch (result) {
545     case GetAppAvailabilityResult::kAvailable:
546       return kGetAppAvailabilityResultAvailableString;
547     case GetAppAvailabilityResult::kUnavailable:
548       return kGetAppAvailabilityResultUnavailableString;
549     default:
550       return nullptr;
551   }
552 }
553
554 base::Optional<int> GetRequestIdFromResponse(const Value& payload) {
555   DCHECK(payload.is_dict());
556
557   const Value* request_id_value =
558       payload.FindKeyOfType("requestId", Value::Type::INTEGER);
559   if (!request_id_value)
560     return base::nullopt;
561   return request_id_value->GetInt();
562 }
563
564 GetAppAvailabilityResult GetAppAvailabilityResultFromResponse(
565     const Value& payload,
566     const std::string& app_id) {
567   DCHECK(payload.is_dict());
568   const Value* availability_value =
569       payload.FindPathOfType({"availability", app_id}, Value::Type::STRING);
570   if (availability_value) {
571     const std::string& result_str = availability_value->GetString();
572     if (result_str == kGetAppAvailabilityResultAvailableString)
573       return GetAppAvailabilityResult::kAvailable;
574     if (result_str == kGetAppAvailabilityResultUnavailableString)
575       return GetAppAvailabilityResult::kUnavailable;
576   }
577   return GetAppAvailabilityResult::kUnknown;
578 }
579
580 LaunchSessionResponse::LaunchSessionResponse() {}
581 LaunchSessionResponse::LaunchSessionResponse(LaunchSessionResponse&& other) =
582     default;
583 LaunchSessionResponse::~LaunchSessionResponse() = default;
584
585 LaunchSessionResponse GetLaunchSessionResponse(const base::Value& payload) {
586   const Value* type_value = payload.FindKeyOfType("type", Value::Type::STRING);
587   if (!type_value)
588     return LaunchSessionResponse();
589
590   CastMessageType type = CastMessageTypeFromString(type_value->GetString());
591   if (type != CastMessageType::kReceiverStatus &&
592       type != CastMessageType::kLaunchError)
593     return LaunchSessionResponse();
594
595   LaunchSessionResponse response;
596   if (type == CastMessageType::kLaunchError) {
597     response.result = LaunchSessionResponse::Result::kError;
598     return response;
599   }
600
601   const Value* receiver_status =
602       payload.FindKeyOfType("status", Value::Type::DICTIONARY);
603   if (!receiver_status)
604     return LaunchSessionResponse();
605
606   response.result = LaunchSessionResponse::Result::kOk;
607   response.receiver_status = receiver_status->Clone();
608   return response;
609 }
610
611 }  // namespace cast_channel