1 /*
2  * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "context.h"
17 #include "agent/sinkagent/sink_agent.h"
18 #include "agent/srcagent/src_agent.h"
19 #include "common/common_macro.h"
20 #include "common/event_channel.h"
21 #include "common/sharing_log.h"
22 #include "magic_enum.hpp"
23 
24 namespace OHOS {
25 namespace Sharing {
Context()26 Context::Context()
27 {
28     SHARING_LOGD("contextId: %{public}u.", GetId());
29 }
30 
~Context()31 Context::~Context()
32 {
33     SHARING_LOGD("contextId: %{public}u.", GetId());
34 }
35 
Release()36 void Context::Release()
37 {
38     SHARING_LOGD("contextId: %{public}u.", GetId());
39     destroying_ = true;
40     std::lock_guard<std::mutex> lock(mutex_);
41     if (agents_.size()) {
42         SHARING_LOGW("exception to enter! contextId: %{public}u.", GetId());
43     }
44     agents_.clear();
45 }
46 
HandleEvent(SharingEvent &event)47 int32_t Context::HandleEvent(SharingEvent &event)
48 {
49     SHARING_LOGD("trace.");
50     RETURN_INVALID_IF_NULL(event.eventMsg);
51     SHARING_LOGI(
52         "contextId: %{public}u, fromMgr: %{public}u, srcId: %{public}u, "
53         "toMgr: %{public}u, toId: %{public}u, event: %{public}s.",
54         GetId(), event.eventMsg->fromMgr, event.eventMsg->srcId, event.eventMsg->toMgr, event.eventMsg->dstId,
55         std::string(magic_enum::enum_name(event.eventMsg->type)).c_str());
56     if (destroying_) {
57         SHARING_LOGW("destroying contextId: %{public}u.", GetId());
58         return -1;
59     }
60 
61     switch (event.eventMsg->type) {
62         case EventType::EVENT_CONTEXT_AGENT_CREATE: {
63             auto eventMsg = ConvertEventMsg<ContextEventMsg>(event);
64             if (eventMsg) {
65                 interactionId_ = eventMsg->srcId;
66                 eventMsg->agentId = HandleCreateAgent(eventMsg->className, eventMsg->agentType, eventMsg->agentId);
67             }
68             break;
69         }
70         case EventType::EVENT_CONTEXT_AGENT_DESTROY:
71             HandleAgentDestroy(event);
72             break;
73         case EventType::EVENT_CONTEXT_STATE_AGENT_DESTROY:
74             HandleStateDestroyAgent(event);
75             break;
76         default:
77             DistributeEvent(event);
78             break;
79     }
80 
81     return 0;
82 }
83 
HandleAgentDestroy(SharingEvent &event)84 void Context::HandleAgentDestroy(SharingEvent &event)
85 {
86     SHARING_LOGD("trace.");
87     RETURN_IF_NULL(event.eventMsg);
88     auto eventMsg = ConvertEventMsg<AgentEventMsg>(event);
89     if (eventMsg == nullptr) {
90         SHARING_LOGE("msg null.");
91         return;
92     }
93 
94     SHARING_LOGI("contextId: %{public}u, destroy agent agentId: %{public}u.", GetId(), eventMsg->agentId);
95     interactionId_ = eventMsg->srcId;
96     auto agent = GetAgentById(eventMsg->agentId);
97     if (agent == nullptr) {
98         SHARING_LOGE("agent null agentId: %{public}d.", eventMsg->agentId);
99         return;
100     }
101 
102     if (agent->GetAgentType() == SRC_AGENT) {
103         event.eventMsg->type = EVENT_AGENT_DESTROY;
104         agent->HandleEvent(event);
105     } else {
106         agent->SetDestroy();
107         if (IsEmptySrcAgent(eventMsg->agentId)) {
108             event.eventMsg->type = EVENT_AGENT_DESTROY;
109             agent->HandleEvent(event);
110         } else {
111             SHARING_LOGI("contextId: %{public}u, destroy agent need wait src agent destroy. agentId: %{public}u.",
112                          GetId(), eventMsg->agentId);
113             std::lock_guard<std::mutex> lock(mutex_);
114             for (auto item : agents_) {
115                 if (item.second->GetAgentType() == SRC_AGENT) {
116                     event.eventMsg->type = EVENT_AGENT_DESTROY;
117                     item.second->HandleEvent(event);
118                 }
119             }
120         }
121     }
122 }
123 
DistributeEvent(SharingEvent &event)124 void Context::DistributeEvent(SharingEvent &event)
125 {
126     SHARING_LOGD("trace.");
127     auto eventMsg = ConvertEventMsg<AgentEventMsg>(event);
128     if (eventMsg) {
129         auto agent = GetAgentById(eventMsg->agentId);
130         if (agent) {
131             agent->HandleEvent(event);
132         }
133     }
134 }
135 
IsEmptySrcAgent(uint32_t sinkAgentId)136 bool Context::IsEmptySrcAgent(uint32_t sinkAgentId)
137 {
138     SHARING_LOGD("trace.");
139     std::lock_guard<std::mutex> lock(mutex_);
140     for (auto &item : agents_) {
141         if (item.second->GetAgentType() == SRC_AGENT) {
142             auto srcAgent = std::static_pointer_cast<SrcAgent>(item.second);
143             if (srcAgent && srcAgent->GetSinkAgentId() == sinkAgentId) {
144                 return false;
145             }
146         }
147     }
148 
149     return true;
150 }
151 
GetSinkAgentSize()152 int32_t Context::GetSinkAgentSize()
153 {
154     SHARING_LOGD("trace.");
155     std::lock_guard<std::mutex> lock(mutex_);
156     int32_t agentSize = 0;
157     for (auto &item : agents_) {
158         if (item.second->GetAgentType() == SINK_AGENT) {
159             SHARING_LOGD("agent id still has %{public}d.", item.second->GetId());
160             ++agentSize;
161         }
162     }
163 
164     return agentSize;
165 }
166 
GetSrcAgentSize()167 int32_t Context::GetSrcAgentSize()
168 {
169     SHARING_LOGD("trace.");
170     std::lock_guard<std::mutex> lock(mutex_);
171     int32_t agentSize = 0;
172     for (auto &item : agents_) {
173         if (item.second->GetAgentType() == SRC_AGENT) {
174             ++agentSize;
175         }
176     }
177 
178     return agentSize;
179 }
180 
SendInteractionEvent(EventType eventType, ContextEventMsg::Ptr &eventMsg)181 void Context::SendInteractionEvent(EventType eventType, ContextEventMsg::Ptr &eventMsg)
182 {
183     SHARING_LOGD("trace.");
184     auto interactionMsg = std::make_shared<InteractionEventMsg>();
185     interactionMsg->fromMgr = ModuleType::MODULE_CONTEXT;
186     interactionMsg->srcId = GetId();
187     interactionMsg->toMgr = ModuleType::MODULE_INTERACTION;
188     interactionMsg->dstId = interactionId_;
189 
190     interactionMsg->type = eventType;
191     interactionMsg->errorCode = eventMsg->errorCode;
192     interactionMsg->agentId = eventMsg->agentId;
193     interactionMsg->agentType = eventMsg->agentType;
194     interactionMsg->contextId = GetId();
195     interactionMsg->surfaceId = eventMsg->surfaceId;
196 
197     SharingEvent event;
198     event.eventMsg = std::move(interactionMsg);
199     SendEvent(event);
200     SHARING_LOGI("event: %{public}u is sended by contextId: %{public}u.", event.eventMsg->type, GetId());
201 }
202 
IsEmptyAgent()203 bool Context::IsEmptyAgent()
204 {
205     SHARING_LOGD("trace.");
206     std::lock_guard<std::mutex> lock(mutex_);
207     return agents_.size() == 0;
208 }
209 
OnAgentNotify(AgentStatusMsg::Ptr &statusMsg)210 void Context::OnAgentNotify(AgentStatusMsg::Ptr &statusMsg)
211 {
212     SHARING_LOGD("trace.");
213     RETURN_IF_NULL(statusMsg);
214     RETURN_IF_NULL(statusMsg->msg);
215     SHARING_LOGI("contextId: %{public}u, agentId: %{public}u, toMgr: %{public}u, dstId: %{public}u, event: %{public}s.",
216                  GetId(), statusMsg->agentId, statusMsg->msg->toMgr, statusMsg->msg->dstId,
217                  std::string(magic_enum::enum_name(statusMsg->msg->type)).c_str());
218 
219     if (statusMsg->msg) {
220         if (statusMsg->msg->toMgr == ModuleType::MODULE_INTERACTION) {
221             statusMsg->msg->dstId = interactionId_;
222             auto interactionMsg = std::static_pointer_cast<InteractionEventMsg>(statusMsg->msg);
223             RETURN_IF_NULL(interactionMsg);
224             interactionMsg->contextId = GetId();
225         } else if (statusMsg->msg->toMgr == ModuleType::MODULE_CONTEXT) {
226             statusMsg->msg->dstId = GetId();
227         }
228 
229         SharingEvent event;
230         event.eventMsg = std::move(statusMsg->msg);
231         event.eventMsg->fromMgr = ModuleType::MODULE_CONTEXT;
232         event.eventMsg->srcId = GetId();
233 
234         SendEvent(event);
235         SHARING_LOGI("event: %{public}s is sended by contextId: %{public}u.",
236                      std::string(magic_enum::enum_name(event.eventMsg->type)).c_str(), GetId());
237     }
238 }
239 
HandleCreateAgent(const std::string &className, AgentType agentType, uint32_t sinkAgentId)240 uint32_t Context::HandleCreateAgent(const std::string &className, AgentType agentType, uint32_t sinkAgentId)
241 {
242     SHARING_LOGI("contextId: %{public}u, agentType: %{public}s, sinkAgentId: %{public}u.", GetId(),
243                  std::string(magic_enum::enum_name(agentType)).c_str(), sinkAgentId);
244 
245     std::shared_ptr<Agent> agent = nullptr;
246     if (agentType == AgentType::SINK_AGENT) {
247         auto sinkAgent = std::make_shared<SinkAgent>();
248         if (sinkAgent->CreateSession(className) == SharingErrorCode::ERR_SESSION_CREATE) {
249             SHARING_LOGE("create agent session error.");
250             return INVALID_ID;
251         } else {
252             auto channelMsg = std::make_shared<ChannelEventMsg>();
253             channelMsg->agentId = sinkAgent->GetId();
254             channelMsg->toMgr = ModuleType::MODULE_MEDIACHANNEL;
255             channelMsg->type = EVENT_MEDIA_CHANNEL_CREATE;
256 
257             SharingEvent event;
258             event.eventMsg = channelMsg;
259             event.eventMsg->fromMgr = ModuleType::MODULE_CONTEXT;
260             event.eventMsg->toMgr = ModuleType::MODULE_MEDIACHANNEL;
261             event.eventMsg->srcId = GetId();
262             SendSyncEvent(event);
263 
264             SHARING_LOGI("create agent create media channel agentId: %{public}u channelId: %{public}u.",
265                          sinkAgent->GetId(), channelMsg->srcId);
266             sinkAgent->UpdateMediaChannelId(channelMsg->srcId);
267 
268             agent = sinkAgent;
269         }
270     } else {
271         std::lock_guard<std::mutex> lock(mutex_);
272         Agent::Ptr sinkAgent = nullptr;
273         if (agents_.find(sinkAgentId) != agents_.end()) {
274             sinkAgent = agents_.find(sinkAgentId)->second;
275         }
276         if (sinkAgent != nullptr && !sinkAgent->GetDestroy()) {
277             auto srcAgent = std::make_shared<SrcAgent>();
278             if (srcAgent->CreateSession(className) == SharingErrorCode::ERR_SESSION_CREATE) {
279                 SHARING_LOGE("create agent session error.");
280                 return INVALID_ID;
281             } else {
282                 SHARING_LOGI("channelId: %{public}u is set to src agentId: %{public}u.", sinkAgent->GetMediaChannelId(),
283                              srcAgent->GetId());
284                 srcAgent->UpdateMediaChannelId(sinkAgent->GetMediaChannelId());
285                 srcAgent->SetSinkAgentId(sinkAgentId);
286             }
287             agent = srcAgent;
288         } else {
289             SHARING_LOGE("sinkAgentId invalid.");
290             return INVALID_ID;
291         }
292     }
293 
294     agent->SetAgentListener(shared_from_this());
295 
296     std::lock_guard<std::mutex> lock(mutex_);
297     agents_.emplace(agent->GetId(), agent);
298     SHARING_LOGI("contextId: %{public}u, create agent className: %{public}s "
299         "agentType: %{public}s agentId: %{public}u size: %{public}zu.",
300         GetId(), className.c_str(), std::string(magic_enum::enum_name(agentType)).c_str(), agent->GetId(),
301         agents_.size());
302     return agent->GetId();
303 }
304 
GetAgentById(uint32_t agentId)305 Agent::Ptr Context::GetAgentById(uint32_t agentId)
306 {
307     SHARING_LOGD("trace.");
308     std::lock_guard<std::mutex> lock(mutex_);
309     auto itr = agents_.find(agentId);
310     if (itr != agents_.end()) {
311         return itr->second;
312     }
313 
314     return nullptr;
315 }
316 
RemoveAgent(uint32_t agentId)317 void Context::RemoveAgent(uint32_t agentId)
318 {
319     SHARING_LOGD("contextId: %{public}u, remove agentId: %{public}u.", GetId(), agentId);
320     std::lock_guard<std::mutex> lock(mutex_);
321     auto itr = agents_.find(agentId);
322     if (itr != agents_.end()) {
323         agents_.erase(itr);
324     }
325 }
326 
HandleStateDestroyAgent(SharingEvent &event)327 void Context::HandleStateDestroyAgent(SharingEvent &event)
328 {
329     SHARING_LOGD("trace.");
330     auto eventMsg = ConvertEventMsg<ContextEventMsg>(event);
331     if (eventMsg) {
332         auto agent = GetAgentById(eventMsg->agentId);
333         if (agent) {
334             AgentType agentType = agent->GetAgentType();
335             if (agentType == AgentType::SRC_AGENT) {
336                 auto srcAgent = std::static_pointer_cast<SrcAgent>(agent);
337                 uint32_t sinkAgentId = srcAgent->GetSinkAgentId();
338                 RemoveAgent(eventMsg->agentId);
339                 CheckNeedDestroySink(sinkAgentId);
340             } else if (agentType == AgentType::SINK_AGENT) {
341                 RemoveAgent(eventMsg->agentId);
342             }
343 
344             eventMsg->agentType = agentType;
345             SendInteractionEvent(EVENT_INTERACTION_STATE_AGENT_DESTROYED, eventMsg);
346         } else {
347             SHARING_LOGE("agent null agentId: %{public}d.", eventMsg->agentId);
348         }
349     }
350 }
351 
CheckNeedDestroySink(uint32_t sinkAgentId)352 void Context::CheckNeedDestroySink(uint32_t sinkAgentId)
353 {
354     SHARING_LOGD("trace.");
355     auto agent = GetAgentById(sinkAgentId);
356     RETURN_IF_NULL(agent);
357 
358     if (agent->GetDestroy() && IsEmptySrcAgent(sinkAgentId)) {
359         SHARING_LOGI("produer destroyed. src agent is all destroyed. destroy sink agent now. "
360             "contextId: %{public}u, sinkAgentId: %{public}u.", GetId(), sinkAgentId);
361 
362         SharingEvent event;
363         auto agentEvent = std::make_shared<AgentEventMsg>();
364         event.eventMsg = std::move(agentEvent);
365         event.eventMsg->fromMgr = ModuleType::MODULE_CONTEXT;
366         event.eventMsg->srcId = GetId();
367         event.eventMsg->toMgr = ModuleType::MODULE_CONTEXT;
368         event.eventMsg->dstId = GetId();
369         event.eventMsg->type = EVENT_AGENT_DESTROY;
370         agent->HandleEvent(event);
371     }
372 }
373 
374 } // namespace Sharing
375 } // namespace OHOS