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
24namespace OHOS {
25namespace Sharing {
26Context::Context()
27{
28    SHARING_LOGD("contextId: %{public}u.", GetId());
29}
30
31Context::~Context()
32{
33    SHARING_LOGD("contextId: %{public}u.", GetId());
34}
35
36void 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
47int32_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
84void 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
124void 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
136bool 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
152int32_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
167int32_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
181void 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
203bool Context::IsEmptyAgent()
204{
205    SHARING_LOGD("trace.");
206    std::lock_guard<std::mutex> lock(mutex_);
207    return agents_.size() == 0;
208}
209
210void 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
240uint32_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
305Agent::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
317void 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
327void 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
352void 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