xref: /aosp_15_r20/external/openscreen/cast/receiver/application_agent.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "cast/receiver/application_agent.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <utility>
8*3f982cf4SFabien Sanglard 
9*3f982cf4SFabien Sanglard #include "cast/common/channel/message_util.h"
10*3f982cf4SFabien Sanglard #include "cast/common/channel/virtual_connection.h"
11*3f982cf4SFabien Sanglard #include "cast/common/public/cast_socket.h"
12*3f982cf4SFabien Sanglard #include "platform/base/tls_credentials.h"
13*3f982cf4SFabien Sanglard #include "platform/base/tls_listen_options.h"
14*3f982cf4SFabien Sanglard #include "util/json/json_helpers.h"
15*3f982cf4SFabien Sanglard #include "util/json/json_serialization.h"
16*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
17*3f982cf4SFabien Sanglard 
18*3f982cf4SFabien Sanglard namespace openscreen {
19*3f982cf4SFabien Sanglard namespace cast {
20*3f982cf4SFabien Sanglard namespace {
21*3f982cf4SFabien Sanglard 
22*3f982cf4SFabien Sanglard // Returns the first app ID for the given |app|, or the empty string if there is
23*3f982cf4SFabien Sanglard // none.
GetFirstAppId(ApplicationAgent::Application * app)24*3f982cf4SFabien Sanglard std::string GetFirstAppId(ApplicationAgent::Application* app) {
25*3f982cf4SFabien Sanglard   const auto& app_ids = app->GetAppIds();
26*3f982cf4SFabien Sanglard   return app_ids.empty() ? std::string() : app_ids.front();
27*3f982cf4SFabien Sanglard }
28*3f982cf4SFabien Sanglard 
29*3f982cf4SFabien Sanglard }  // namespace
30*3f982cf4SFabien Sanglard 
ApplicationAgent(TaskRunner * task_runner,DeviceAuthNamespaceHandler::CredentialsProvider * credentials_provider)31*3f982cf4SFabien Sanglard ApplicationAgent::ApplicationAgent(
32*3f982cf4SFabien Sanglard     TaskRunner* task_runner,
33*3f982cf4SFabien Sanglard     DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider)
34*3f982cf4SFabien Sanglard     : task_runner_(task_runner),
35*3f982cf4SFabien Sanglard       auth_handler_(credentials_provider),
36*3f982cf4SFabien Sanglard       connection_handler_(&router_, this),
37*3f982cf4SFabien Sanglard       message_port_(&router_) {
38*3f982cf4SFabien Sanglard   router_.AddHandlerForLocalId(kPlatformReceiverId, this);
39*3f982cf4SFabien Sanglard }
40*3f982cf4SFabien Sanglard 
~ApplicationAgent()41*3f982cf4SFabien Sanglard ApplicationAgent::~ApplicationAgent() {
42*3f982cf4SFabien Sanglard   OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
43*3f982cf4SFabien Sanglard 
44*3f982cf4SFabien Sanglard   idle_screen_app_ = nullptr;  // Prevent re-launching the idle screen app.
45*3f982cf4SFabien Sanglard   SwitchToApplication({}, {}, nullptr);
46*3f982cf4SFabien Sanglard 
47*3f982cf4SFabien Sanglard   router_.RemoveHandlerForLocalId(kPlatformReceiverId);
48*3f982cf4SFabien Sanglard }
49*3f982cf4SFabien Sanglard 
RegisterApplication(Application * app,bool auto_launch_for_idle_screen)50*3f982cf4SFabien Sanglard void ApplicationAgent::RegisterApplication(Application* app,
51*3f982cf4SFabien Sanglard                                            bool auto_launch_for_idle_screen) {
52*3f982cf4SFabien Sanglard   OSP_DCHECK(app);
53*3f982cf4SFabien Sanglard 
54*3f982cf4SFabien Sanglard   for (const std::string& app_id : app->GetAppIds()) {
55*3f982cf4SFabien Sanglard     OSP_DCHECK(!app_id.empty());
56*3f982cf4SFabien Sanglard     const auto insert_result = registered_applications_.insert({app_id, app});
57*3f982cf4SFabien Sanglard     // The insert must not fail (prior entry for same key).
58*3f982cf4SFabien Sanglard     OSP_DCHECK(insert_result.second);
59*3f982cf4SFabien Sanglard   }
60*3f982cf4SFabien Sanglard 
61*3f982cf4SFabien Sanglard   if (auto_launch_for_idle_screen) {
62*3f982cf4SFabien Sanglard     OSP_DCHECK(!idle_screen_app_);
63*3f982cf4SFabien Sanglard     idle_screen_app_ = app;
64*3f982cf4SFabien Sanglard     // Launch the idle screen app, if no app was running.
65*3f982cf4SFabien Sanglard     if (!launched_app_) {
66*3f982cf4SFabien Sanglard       GoIdle();
67*3f982cf4SFabien Sanglard     }
68*3f982cf4SFabien Sanglard   }
69*3f982cf4SFabien Sanglard }
70*3f982cf4SFabien Sanglard 
UnregisterApplication(Application * app)71*3f982cf4SFabien Sanglard void ApplicationAgent::UnregisterApplication(Application* app) {
72*3f982cf4SFabien Sanglard   for (auto it = registered_applications_.begin();
73*3f982cf4SFabien Sanglard        it != registered_applications_.end();) {
74*3f982cf4SFabien Sanglard     if (it->second == app) {
75*3f982cf4SFabien Sanglard       it = registered_applications_.erase(it);
76*3f982cf4SFabien Sanglard     } else {
77*3f982cf4SFabien Sanglard       ++it;
78*3f982cf4SFabien Sanglard     }
79*3f982cf4SFabien Sanglard   }
80*3f982cf4SFabien Sanglard 
81*3f982cf4SFabien Sanglard   if (idle_screen_app_ == app) {
82*3f982cf4SFabien Sanglard     idle_screen_app_ = nullptr;
83*3f982cf4SFabien Sanglard   }
84*3f982cf4SFabien Sanglard 
85*3f982cf4SFabien Sanglard   if (launched_app_ == app) {
86*3f982cf4SFabien Sanglard     GoIdle();
87*3f982cf4SFabien Sanglard   }
88*3f982cf4SFabien Sanglard }
89*3f982cf4SFabien Sanglard 
StopApplicationIfRunning(Application * app)90*3f982cf4SFabien Sanglard void ApplicationAgent::StopApplicationIfRunning(Application* app) {
91*3f982cf4SFabien Sanglard   if (launched_app_ == app) {
92*3f982cf4SFabien Sanglard     GoIdle();
93*3f982cf4SFabien Sanglard   }
94*3f982cf4SFabien Sanglard }
95*3f982cf4SFabien Sanglard 
OnConnected(ReceiverSocketFactory * factory,const IPEndpoint & endpoint,std::unique_ptr<CastSocket> socket)96*3f982cf4SFabien Sanglard void ApplicationAgent::OnConnected(ReceiverSocketFactory* factory,
97*3f982cf4SFabien Sanglard                                    const IPEndpoint& endpoint,
98*3f982cf4SFabien Sanglard                                    std::unique_ptr<CastSocket> socket) {
99*3f982cf4SFabien Sanglard   router_.TakeSocket(this, std::move(socket));
100*3f982cf4SFabien Sanglard }
101*3f982cf4SFabien Sanglard 
OnError(ReceiverSocketFactory * factory,Error error)102*3f982cf4SFabien Sanglard void ApplicationAgent::OnError(ReceiverSocketFactory* factory, Error error) {
103*3f982cf4SFabien Sanglard   OSP_LOG_ERROR << "Cast agent received socket factory error: " << error;
104*3f982cf4SFabien Sanglard }
105*3f982cf4SFabien Sanglard 
OnMessage(VirtualConnectionRouter * router,CastSocket * socket,::cast::channel::CastMessage message)106*3f982cf4SFabien Sanglard void ApplicationAgent::OnMessage(VirtualConnectionRouter* router,
107*3f982cf4SFabien Sanglard                                  CastSocket* socket,
108*3f982cf4SFabien Sanglard                                  ::cast::channel::CastMessage message) {
109*3f982cf4SFabien Sanglard   if (message_port_.GetSocketId() == ToCastSocketId(socket) &&
110*3f982cf4SFabien Sanglard       !message_port_.client_sender_id().empty() &&
111*3f982cf4SFabien Sanglard       message_port_.client_sender_id() == message.destination_id()) {
112*3f982cf4SFabien Sanglard     OSP_DCHECK(message_port_.client_sender_id() != kPlatformReceiverId);
113*3f982cf4SFabien Sanglard     message_port_.OnMessage(router, socket, std::move(message));
114*3f982cf4SFabien Sanglard     return;
115*3f982cf4SFabien Sanglard   }
116*3f982cf4SFabien Sanglard 
117*3f982cf4SFabien Sanglard   if (message.destination_id() != kPlatformReceiverId &&
118*3f982cf4SFabien Sanglard       message.destination_id() != kBroadcastId) {
119*3f982cf4SFabien Sanglard     return;  // Message not for us.
120*3f982cf4SFabien Sanglard   }
121*3f982cf4SFabien Sanglard 
122*3f982cf4SFabien Sanglard   const std::string& ns = message.namespace_();
123*3f982cf4SFabien Sanglard   if (ns == kAuthNamespace) {
124*3f982cf4SFabien Sanglard     auth_handler_.OnMessage(router, socket, std::move(message));
125*3f982cf4SFabien Sanglard     return;
126*3f982cf4SFabien Sanglard   }
127*3f982cf4SFabien Sanglard 
128*3f982cf4SFabien Sanglard   const ErrorOr<Json::Value> request = json::Parse(message.payload_utf8());
129*3f982cf4SFabien Sanglard   if (request.is_error() || request.value().type() != Json::objectValue) {
130*3f982cf4SFabien Sanglard     return;
131*3f982cf4SFabien Sanglard   }
132*3f982cf4SFabien Sanglard 
133*3f982cf4SFabien Sanglard   Json::Value response;
134*3f982cf4SFabien Sanglard   if (ns == kHeartbeatNamespace) {
135*3f982cf4SFabien Sanglard     if (HasType(request.value(), CastMessageType::kPing)) {
136*3f982cf4SFabien Sanglard       response = HandlePing();
137*3f982cf4SFabien Sanglard     }
138*3f982cf4SFabien Sanglard   } else if (ns == kReceiverNamespace) {
139*3f982cf4SFabien Sanglard     if (request.value()[kMessageKeyRequestId].isNull()) {
140*3f982cf4SFabien Sanglard       response = HandleInvalidCommand(request.value());
141*3f982cf4SFabien Sanglard     } else if (HasType(request.value(), CastMessageType::kGetAppAvailability)) {
142*3f982cf4SFabien Sanglard       response = HandleGetAppAvailability(request.value());
143*3f982cf4SFabien Sanglard     } else if (HasType(request.value(), CastMessageType::kGetStatus)) {
144*3f982cf4SFabien Sanglard       response = HandleGetStatus(request.value());
145*3f982cf4SFabien Sanglard     } else if (HasType(request.value(), CastMessageType::kLaunch)) {
146*3f982cf4SFabien Sanglard       response = HandleLaunch(request.value(), socket);
147*3f982cf4SFabien Sanglard     } else if (HasType(request.value(), CastMessageType::kStop)) {
148*3f982cf4SFabien Sanglard       response = HandleStop(request.value());
149*3f982cf4SFabien Sanglard     } else {
150*3f982cf4SFabien Sanglard       response = HandleInvalidCommand(request.value());
151*3f982cf4SFabien Sanglard     }
152*3f982cf4SFabien Sanglard   } else {
153*3f982cf4SFabien Sanglard     // Ignore messages for all other namespaces.
154*3f982cf4SFabien Sanglard   }
155*3f982cf4SFabien Sanglard 
156*3f982cf4SFabien Sanglard   if (!response.empty()) {
157*3f982cf4SFabien Sanglard     router_.Send(VirtualConnection{message.destination_id(),
158*3f982cf4SFabien Sanglard                                    message.source_id(), ToCastSocketId(socket)},
159*3f982cf4SFabien Sanglard                  MakeSimpleUTF8Message(ns, json::Stringify(response).value()));
160*3f982cf4SFabien Sanglard   }
161*3f982cf4SFabien Sanglard }
162*3f982cf4SFabien Sanglard 
IsConnectionAllowed(const VirtualConnection & virtual_conn) const163*3f982cf4SFabien Sanglard bool ApplicationAgent::IsConnectionAllowed(
164*3f982cf4SFabien Sanglard     const VirtualConnection& virtual_conn) const {
165*3f982cf4SFabien Sanglard   if (virtual_conn.local_id == kPlatformReceiverId) {
166*3f982cf4SFabien Sanglard     return true;
167*3f982cf4SFabien Sanglard   }
168*3f982cf4SFabien Sanglard   if (!launched_app_ || message_port_.client_sender_id().empty()) {
169*3f982cf4SFabien Sanglard     // No app currently launched. Or, there is a launched app, but it did not
170*3f982cf4SFabien Sanglard     // call MessagePort::SetClient() to indicate it wants messages routed to it.
171*3f982cf4SFabien Sanglard     return false;
172*3f982cf4SFabien Sanglard   }
173*3f982cf4SFabien Sanglard   return virtual_conn.local_id == message_port_.client_sender_id();
174*3f982cf4SFabien Sanglard }
175*3f982cf4SFabien Sanglard 
OnClose(CastSocket * socket)176*3f982cf4SFabien Sanglard void ApplicationAgent::OnClose(CastSocket* socket) {
177*3f982cf4SFabien Sanglard   if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
178*3f982cf4SFabien Sanglard     OSP_VLOG << "Cast agent socket closed.";
179*3f982cf4SFabien Sanglard     GoIdle();
180*3f982cf4SFabien Sanglard   }
181*3f982cf4SFabien Sanglard }
182*3f982cf4SFabien Sanglard 
OnError(CastSocket * socket,Error error)183*3f982cf4SFabien Sanglard void ApplicationAgent::OnError(CastSocket* socket, Error error) {
184*3f982cf4SFabien Sanglard   if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
185*3f982cf4SFabien Sanglard     OSP_LOG_ERROR << "Cast agent received socket error: " << error;
186*3f982cf4SFabien Sanglard     GoIdle();
187*3f982cf4SFabien Sanglard   }
188*3f982cf4SFabien Sanglard }
189*3f982cf4SFabien Sanglard 
HandlePing()190*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandlePing() {
191*3f982cf4SFabien Sanglard   Json::Value response;
192*3f982cf4SFabien Sanglard   response[kMessageKeyType] = CastMessageTypeToString(CastMessageType::kPong);
193*3f982cf4SFabien Sanglard   return response;
194*3f982cf4SFabien Sanglard }
195*3f982cf4SFabien Sanglard 
HandleGetAppAvailability(const Json::Value & request)196*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandleGetAppAvailability(
197*3f982cf4SFabien Sanglard     const Json::Value& request) {
198*3f982cf4SFabien Sanglard   Json::Value response;
199*3f982cf4SFabien Sanglard   const Json::Value& app_ids = request[kMessageKeyAppId];
200*3f982cf4SFabien Sanglard   if (app_ids.isArray()) {
201*3f982cf4SFabien Sanglard     response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
202*3f982cf4SFabien Sanglard     response[kMessageKeyResponseType] = request[kMessageKeyType];
203*3f982cf4SFabien Sanglard     Json::Value& availability = response[kMessageKeyAvailability];
204*3f982cf4SFabien Sanglard     for (const Json::Value& app_id : app_ids) {
205*3f982cf4SFabien Sanglard       if (app_id.isString()) {
206*3f982cf4SFabien Sanglard         const auto app_id_str = app_id.asString();
207*3f982cf4SFabien Sanglard         availability[app_id_str] = registered_applications_.count(app_id_str)
208*3f982cf4SFabien Sanglard                                        ? kMessageValueAppAvailable
209*3f982cf4SFabien Sanglard                                        : kMessageValueAppUnavailable;
210*3f982cf4SFabien Sanglard       }
211*3f982cf4SFabien Sanglard     }
212*3f982cf4SFabien Sanglard   }
213*3f982cf4SFabien Sanglard   return response;
214*3f982cf4SFabien Sanglard }
215*3f982cf4SFabien Sanglard 
HandleGetStatus(const Json::Value & request)216*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandleGetStatus(const Json::Value& request) {
217*3f982cf4SFabien Sanglard   Json::Value response;
218*3f982cf4SFabien Sanglard   PopulateReceiverStatus(&response);
219*3f982cf4SFabien Sanglard   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
220*3f982cf4SFabien Sanglard   return response;
221*3f982cf4SFabien Sanglard }
222*3f982cf4SFabien Sanglard 
HandleLaunch(const Json::Value & request,CastSocket * socket)223*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandleLaunch(const Json::Value& request,
224*3f982cf4SFabien Sanglard                                            CastSocket* socket) {
225*3f982cf4SFabien Sanglard   const Json::Value& app_id = request[kMessageKeyAppId];
226*3f982cf4SFabien Sanglard   Error error;
227*3f982cf4SFabien Sanglard   if (app_id.isString() && !app_id.asString().empty()) {
228*3f982cf4SFabien Sanglard     error = SwitchToApplication(app_id.asString(),
229*3f982cf4SFabien Sanglard                                 request[kMessageKeyAppParams], socket);
230*3f982cf4SFabien Sanglard   } else {
231*3f982cf4SFabien Sanglard     error = Error(Error::Code::kParameterInvalid, kMessageValueBadParameter);
232*3f982cf4SFabien Sanglard   }
233*3f982cf4SFabien Sanglard   if (!error.ok()) {
234*3f982cf4SFabien Sanglard     Json::Value response;
235*3f982cf4SFabien Sanglard     response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
236*3f982cf4SFabien Sanglard     response[kMessageKeyType] =
237*3f982cf4SFabien Sanglard         CastMessageTypeToString(CastMessageType::kLaunchError);
238*3f982cf4SFabien Sanglard     response[kMessageKeyReason] = error.message();
239*3f982cf4SFabien Sanglard     return response;
240*3f982cf4SFabien Sanglard   }
241*3f982cf4SFabien Sanglard 
242*3f982cf4SFabien Sanglard   // Note: No reply is sent. Instead, the requestor will get a RECEIVER_STATUS
243*3f982cf4SFabien Sanglard   // broadcast message from SwitchToApplication(), which is how it will see that
244*3f982cf4SFabien Sanglard   // the launch succeeded.
245*3f982cf4SFabien Sanglard   return {};
246*3f982cf4SFabien Sanglard }
247*3f982cf4SFabien Sanglard 
HandleStop(const Json::Value & request)248*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandleStop(const Json::Value& request) {
249*3f982cf4SFabien Sanglard   const Json::Value& session_id = request[kMessageKeySessionId];
250*3f982cf4SFabien Sanglard   if (session_id.isNull()) {
251*3f982cf4SFabien Sanglard     GoIdle();
252*3f982cf4SFabien Sanglard     return {};
253*3f982cf4SFabien Sanglard   }
254*3f982cf4SFabien Sanglard 
255*3f982cf4SFabien Sanglard   if (session_id.isString() && launched_app_ &&
256*3f982cf4SFabien Sanglard       session_id.asString() == launched_app_->GetSessionId()) {
257*3f982cf4SFabien Sanglard     GoIdle();
258*3f982cf4SFabien Sanglard     return {};
259*3f982cf4SFabien Sanglard   }
260*3f982cf4SFabien Sanglard 
261*3f982cf4SFabien Sanglard   Json::Value response;
262*3f982cf4SFabien Sanglard   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
263*3f982cf4SFabien Sanglard   response[kMessageKeyType] =
264*3f982cf4SFabien Sanglard       CastMessageTypeToString(CastMessageType::kInvalidRequest);
265*3f982cf4SFabien Sanglard   response[kMessageKeyReason] = kMessageValueInvalidSessionId;
266*3f982cf4SFabien Sanglard   return response;
267*3f982cf4SFabien Sanglard }
268*3f982cf4SFabien Sanglard 
HandleInvalidCommand(const Json::Value & request)269*3f982cf4SFabien Sanglard Json::Value ApplicationAgent::HandleInvalidCommand(const Json::Value& request) {
270*3f982cf4SFabien Sanglard   Json::Value response;
271*3f982cf4SFabien Sanglard   if (request[kMessageKeyRequestId].isNull()) {
272*3f982cf4SFabien Sanglard     return response;
273*3f982cf4SFabien Sanglard   }
274*3f982cf4SFabien Sanglard   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
275*3f982cf4SFabien Sanglard   response[kMessageKeyType] =
276*3f982cf4SFabien Sanglard       CastMessageTypeToString(CastMessageType::kInvalidRequest);
277*3f982cf4SFabien Sanglard   response[kMessageKeyReason] = kMessageValueInvalidCommand;
278*3f982cf4SFabien Sanglard   return response;
279*3f982cf4SFabien Sanglard }
280*3f982cf4SFabien Sanglard 
SwitchToApplication(std::string app_id,const Json::Value & app_params,CastSocket * socket)281*3f982cf4SFabien Sanglard Error ApplicationAgent::SwitchToApplication(std::string app_id,
282*3f982cf4SFabien Sanglard                                             const Json::Value& app_params,
283*3f982cf4SFabien Sanglard                                             CastSocket* socket) {
284*3f982cf4SFabien Sanglard   Error error = Error::Code::kNone;
285*3f982cf4SFabien Sanglard   Application* desired_app = nullptr;
286*3f982cf4SFabien Sanglard   Application* fallback_app = nullptr;
287*3f982cf4SFabien Sanglard   if (!app_id.empty()) {
288*3f982cf4SFabien Sanglard     const auto it = registered_applications_.find(app_id);
289*3f982cf4SFabien Sanglard     if (it != registered_applications_.end()) {
290*3f982cf4SFabien Sanglard       desired_app = it->second;
291*3f982cf4SFabien Sanglard       if (desired_app != idle_screen_app_) {
292*3f982cf4SFabien Sanglard         fallback_app = idle_screen_app_;
293*3f982cf4SFabien Sanglard       }
294*3f982cf4SFabien Sanglard     } else {
295*3f982cf4SFabien Sanglard       return Error(Error::Code::kItemNotFound, kMessageValueNotFound);
296*3f982cf4SFabien Sanglard     }
297*3f982cf4SFabien Sanglard   }
298*3f982cf4SFabien Sanglard 
299*3f982cf4SFabien Sanglard   if (launched_app_ == desired_app) {
300*3f982cf4SFabien Sanglard     return error;
301*3f982cf4SFabien Sanglard   }
302*3f982cf4SFabien Sanglard 
303*3f982cf4SFabien Sanglard   if (launched_app_) {
304*3f982cf4SFabien Sanglard     launched_app_->Stop();
305*3f982cf4SFabien Sanglard     message_port_.SetSocket({});
306*3f982cf4SFabien Sanglard     launched_app_ = nullptr;
307*3f982cf4SFabien Sanglard     launched_via_app_id_ = {};
308*3f982cf4SFabien Sanglard   }
309*3f982cf4SFabien Sanglard 
310*3f982cf4SFabien Sanglard   if (desired_app) {
311*3f982cf4SFabien Sanglard     if (socket) {
312*3f982cf4SFabien Sanglard       message_port_.SetSocket(socket->GetWeakPtr());
313*3f982cf4SFabien Sanglard     }
314*3f982cf4SFabien Sanglard     if (desired_app->Launch(app_id, app_params, &message_port_)) {
315*3f982cf4SFabien Sanglard       launched_app_ = desired_app;
316*3f982cf4SFabien Sanglard       launched_via_app_id_ = std::move(app_id);
317*3f982cf4SFabien Sanglard     } else {
318*3f982cf4SFabien Sanglard       error = Error(Error::Code::kUnknownError, kMessageValueSystemError);
319*3f982cf4SFabien Sanglard       message_port_.SetSocket({});
320*3f982cf4SFabien Sanglard     }
321*3f982cf4SFabien Sanglard   }
322*3f982cf4SFabien Sanglard 
323*3f982cf4SFabien Sanglard   if (!launched_app_ && fallback_app) {
324*3f982cf4SFabien Sanglard     app_id = GetFirstAppId(fallback_app);
325*3f982cf4SFabien Sanglard     if (fallback_app->Launch(app_id, {}, &message_port_)) {
326*3f982cf4SFabien Sanglard       launched_app_ = fallback_app;
327*3f982cf4SFabien Sanglard       launched_via_app_id_ = std::move(app_id);
328*3f982cf4SFabien Sanglard     }
329*3f982cf4SFabien Sanglard   }
330*3f982cf4SFabien Sanglard 
331*3f982cf4SFabien Sanglard   BroadcastReceiverStatus();
332*3f982cf4SFabien Sanglard 
333*3f982cf4SFabien Sanglard   return error;
334*3f982cf4SFabien Sanglard }
335*3f982cf4SFabien Sanglard 
GoIdle()336*3f982cf4SFabien Sanglard void ApplicationAgent::GoIdle() {
337*3f982cf4SFabien Sanglard   std::string app_id;
338*3f982cf4SFabien Sanglard   if (idle_screen_app_) {
339*3f982cf4SFabien Sanglard     app_id = GetFirstAppId(idle_screen_app_);
340*3f982cf4SFabien Sanglard   }
341*3f982cf4SFabien Sanglard   SwitchToApplication(app_id, {}, nullptr);
342*3f982cf4SFabien Sanglard }
343*3f982cf4SFabien Sanglard 
PopulateReceiverStatus(Json::Value * out)344*3f982cf4SFabien Sanglard void ApplicationAgent::PopulateReceiverStatus(Json::Value* out) {
345*3f982cf4SFabien Sanglard   Json::Value& message = *out;
346*3f982cf4SFabien Sanglard   message[kMessageKeyType] =
347*3f982cf4SFabien Sanglard       CastMessageTypeToString(CastMessageType::kReceiverStatus);
348*3f982cf4SFabien Sanglard   Json::Value& status = message[kMessageKeyStatus];
349*3f982cf4SFabien Sanglard 
350*3f982cf4SFabien Sanglard   if (launched_app_) {
351*3f982cf4SFabien Sanglard     Json::Value& details = status[kMessageKeyApplications][0];
352*3f982cf4SFabien Sanglard     // If the Application can send/receive messages, the destination for such
353*3f982cf4SFabien Sanglard     // messages is provided here, in |transportId|. However, the other end must
354*3f982cf4SFabien Sanglard     // first set up the virtual connection by issuing a CONNECT request.
355*3f982cf4SFabien Sanglard     // Otherwise, messages will not get routed to the Application by the
356*3f982cf4SFabien Sanglard     // VirtualConnectionRouter.
357*3f982cf4SFabien Sanglard     if (!message_port_.client_sender_id().empty()) {
358*3f982cf4SFabien Sanglard       details[kMessageKeyTransportId] = message_port_.client_sender_id();
359*3f982cf4SFabien Sanglard     }
360*3f982cf4SFabien Sanglard     details[kMessageKeySessionId] = launched_app_->GetSessionId();
361*3f982cf4SFabien Sanglard     details[kMessageKeyAppId] = launched_via_app_id_;
362*3f982cf4SFabien Sanglard     details[kMessageKeyUniversalAppId] = launched_via_app_id_;
363*3f982cf4SFabien Sanglard     details[kMessageKeyDisplayName] = launched_app_->GetDisplayName();
364*3f982cf4SFabien Sanglard     details[kMessageKeyIsIdleScreen] = (launched_app_ == idle_screen_app_);
365*3f982cf4SFabien Sanglard     details[kMessageKeyLaunchedFromCloud] = false;
366*3f982cf4SFabien Sanglard     std::vector<std::string> app_namespaces =
367*3f982cf4SFabien Sanglard         launched_app_->GetSupportedNamespaces();
368*3f982cf4SFabien Sanglard     Json::Value& namespaces =
369*3f982cf4SFabien Sanglard         (details[kMessageKeyNamespaces] = Json::Value(Json::arrayValue));
370*3f982cf4SFabien Sanglard     for (int i = 0, count = app_namespaces.size(); i < count; ++i) {
371*3f982cf4SFabien Sanglard       namespaces[i][kMessageKeyName] = std::move(app_namespaces[i]);
372*3f982cf4SFabien Sanglard     }
373*3f982cf4SFabien Sanglard   }
374*3f982cf4SFabien Sanglard 
375*3f982cf4SFabien Sanglard   status[kMessageKeyUserEq] = Json::Value(Json::objectValue);
376*3f982cf4SFabien Sanglard 
377*3f982cf4SFabien Sanglard   // Indicate a fixed 100% volume level.
378*3f982cf4SFabien Sanglard   Json::Value& volume = status[kMessageKeyVolume];
379*3f982cf4SFabien Sanglard   volume[kMessageKeyControlType] = kMessageValueAttenuation;
380*3f982cf4SFabien Sanglard   volume[kMessageKeyLevel] = 1.0;
381*3f982cf4SFabien Sanglard   volume[kMessageKeyMuted] = false;
382*3f982cf4SFabien Sanglard   volume[kMessageKeyStepInterval] = 0.05;
383*3f982cf4SFabien Sanglard }
384*3f982cf4SFabien Sanglard 
BroadcastReceiverStatus()385*3f982cf4SFabien Sanglard void ApplicationAgent::BroadcastReceiverStatus() {
386*3f982cf4SFabien Sanglard   Json::Value message;
387*3f982cf4SFabien Sanglard   PopulateReceiverStatus(&message);
388*3f982cf4SFabien Sanglard   message[kMessageKeyRequestId] = Json::Value(0);  // Indicates no requestor.
389*3f982cf4SFabien Sanglard   router_.BroadcastFromLocalPeer(
390*3f982cf4SFabien Sanglard       kPlatformReceiverId,
391*3f982cf4SFabien Sanglard       MakeSimpleUTF8Message(kReceiverNamespace,
392*3f982cf4SFabien Sanglard                             json::Stringify(message).value()));
393*3f982cf4SFabien Sanglard }
394*3f982cf4SFabien Sanglard 
395*3f982cf4SFabien Sanglard ApplicationAgent::Application::~Application() = default;
396*3f982cf4SFabien Sanglard 
397*3f982cf4SFabien Sanglard }  // namespace cast
398*3f982cf4SFabien Sanglard }  // namespace openscreen
399