1/*
2 * Copyright (c) 2024 Huawei Device 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 * Description: Cast Session states realization.
15 * Author: zhangge
16 * Create: 2022-07-19
17 */
18
19#include "cast_session_impl.h"
20#include "cast_engine_log.h"
21#include "cast_engine_dfx.h"
22
23namespace OHOS {
24namespace CastEngine {
25namespace CastEngineService {
26DEFINE_CAST_ENGINE_LABEL("Cast-Session-State");
27
28void CastSessionImpl::BaseState::Enter(SessionState state)
29{
30    auto session = session_.promote();
31    if (!session) {
32        CLOGE("Session is invalid");
33        return;
34    }
35
36    // BaseState and its inherited classes work under the strict control of the session,
37    // so the session_ used in the BaseState member function must not be null.
38    session->sessionState_ = state;
39    CLOGI("%s enter", SESSION_STATE_STRING[static_cast<int>(state)].c_str());
40}
41
42void CastSessionImpl::BaseState::Exit()
43{
44    auto session = session_.promote();
45    if (!session) {
46        CLOGE("Session is invalid");
47        return;
48    }
49
50    CLOGI("%s exit", SESSION_STATE_STRING[static_cast<int>(session->sessionState_)].c_str());
51}
52
53bool CastSessionImpl::BaseState::HandleMessage(const Message &msg)
54{
55    auto session = session_.promote();
56    if (!session) {
57        CLOGE("Session is invalid");
58        return false;
59    }
60
61    CLOGI("msg: %s, session state: %s", session->MESSAGE_ID_STRING[msg.what_].c_str(),
62        SESSION_STATE_STRING[static_cast<int>(session->sessionState_)].c_str());
63    return true;
64}
65
66SessionState CastSessionImpl::BaseState::GetStateId() const
67{
68    return stateId_;
69}
70
71void CastSessionImpl::DefaultState::Enter()
72{
73    BaseState::Enter(SessionState::DEFAULT);
74}
75
76void CastSessionImpl::DefaultState::Exit()
77{
78    BaseState::Exit();
79}
80
81bool CastSessionImpl::DefaultState::HandleMessage(const Message &msg)
82{
83    auto session = session_.promote();
84    if (!session) {
85        CLOGE("Session is invalid");
86        return false;
87    }
88
89    BaseState::HandleMessage(msg);
90
91    MessageId msgId = static_cast<MessageId>(msg.what_);
92    switch (msgId) {
93        case MessageId::MSG_CONNECT_TIMEOUT:
94            session->ProcessStateEvent(MessageId::MSG_CONNECT_TIMEOUT, msg);
95            break;
96        default:
97            CLOGW("unsupported msg: %s, in default state", MESSAGE_ID_STRING[msgId].c_str());
98            return false;
99    }
100    return true;
101}
102
103void CastSessionImpl::DisconnectedState::Enter()
104{
105    BaseState::Enter(SessionState::DISCONNECTED);
106}
107
108void CastSessionImpl::DisconnectedState::Exit()
109{
110    BaseState::Exit();
111}
112
113bool CastSessionImpl::DisconnectedState::HandleMessage(const Message &msg)
114{
115    auto session = session_.promote();
116    if (!session) {
117        CLOGE("Session is invalid");
118        return false;
119    }
120
121    BaseState::HandleMessage(msg);
122
123    MessageId msgId = static_cast<MessageId>(msg.what_);
124    std::string deviceId = msg.strArg_;
125    switch (msgId) {
126        case MessageId::MSG_AUTH:
127                session->TransferTo(session->authingState_);
128            break;
129        case MessageId::MSG_CONNECT:
130            if (session->ProcessConnect(msg) >= 0) {
131                session->ChangeDeviceState(DeviceState::CONNECTING, deviceId);
132                session->SendCastMessageDelayed(MessageId::MSG_CONNECT_TIMEOUT, TIMEOUT_CONNECT);
133                session->TransferTo(session->connectingState_);
134            } else {
135                // Connection failed
136                session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId);
137            }
138            break;
139        default:
140            CLOGW("unsupported msg: %s, in disconnected state", MESSAGE_ID_STRING[msgId].c_str());
141            return false;
142    }
143    return true;
144}
145
146void CastSessionImpl::AuthingState::Enter()
147{
148    BaseState::Enter(SessionState::AUTHING);
149}
150
151void CastSessionImpl::AuthingState::Exit()
152{
153    BaseState::Exit();
154}
155
156bool CastSessionImpl::AuthingState::HandleMessage(const Message &msg)
157{
158    auto session = session_.promote();
159    if (!session) {
160        CLOGE("Session is invalid");
161        return false;
162    }
163
164    BaseState::HandleMessage(msg);
165
166    MessageId msgId = static_cast<MessageId>(msg.what_);
167    std::string deviceId = msg.strArg_;
168    switch (msgId) {
169        case MessageId::MSG_CONNECT: {
170            int port = session->ProcessConnect(msg);
171            if (port >= 0) {
172                session->ChangeDeviceState(DeviceState::CONNECTING, deviceId);
173                session->SendCastMessageDelayed(MessageId::MSG_CONNECT_TIMEOUT, TIMEOUT_CONNECT);
174                session->TransferTo(session->connectingState_);
175                session->SendConsultData(deviceId, port);
176            } else {
177                session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId);
178            }
179            break;
180        }
181        case MessageId::MSG_DISCONNECT:
182        case MessageId::MSG_CONNECT_TIMEOUT:
183            session->ProcessDisconnect(msg);
184            session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId, msg.eventCode_);
185            session->RemoveRemoteDevice(deviceId);
186            session->TransferTo(session->disconnectingState_);
187            break;
188        case MessageId::MSG_ERROR:
189            session->ProcessError(msg);
190            session->TransferTo(session->disconnectingState_);
191            break;
192        case MessageId::MSG_AUTH:
193            session->ReportDeviceStateInfo(DeviceState::AUTHING, deviceId, msg.eventCode_);
194            break;
195        default:
196            CLOGW("unsupported msg: %s, in authing state", MESSAGE_ID_STRING[msgId].c_str());
197            return false;
198    }
199    return true;
200}
201
202
203void CastSessionImpl::ConnectingState::Enter()
204{
205    BaseState::Enter(SessionState::CONNECTING);
206}
207
208void CastSessionImpl::ConnectingState::Exit()
209{
210    BaseState::Exit();
211}
212
213bool CastSessionImpl::ConnectingState::HandleMessage(const Message &msg)
214{
215    auto session = session_.promote();
216    if (!session) {
217        CLOGE("Session is invalid");
218        return false;
219    }
220    BaseState::HandleMessage(msg);
221    MessageId msgId = static_cast<MessageId>(msg.what_);
222    switch (msgId) {
223        case MessageId::MSG_SETUP:
224            HandleSetupMessage(msg, session);
225            break;
226        case MessageId::MSG_SETUP_SUCCESS:
227            HandleSetupSuccessMessage(msg, msgId, session);
228            break;
229        case MessageId::MSG_DISCONNECT:
230        case MessageId::MSG_CONNECT_TIMEOUT:
231            HandleDisconnectMessage(msg, session);
232            break;
233        case MessageId::MSG_ERROR:
234            HandleErrorMessage(msg, session);
235            break;
236        case MessageId::MSG_PEER_RENDER_READY:
237            HandleRenderReadyMessage(msg, session);
238            break;
239        case MessageId::MSG_CONNECT:
240        case MessageId::MSG_PLAY:
241        case MessageId::MSG_PLAY_REQ:
242            HandleConnectMessage(msg, msgId, session);
243            break;
244        default:
245            CLOGW("unsupported msg: %s, in connecting state", MESSAGE_ID_STRING[msgId].c_str());
246            return false;
247    }
248    return true;
249}
250
251void CastSessionImpl::ConnectingState::HandleSetupMessage(const Message &msg, sptr<CastSessionImpl> session)
252{
253    if (!session) {
254        CLOGE("Session is invalid");
255        return;
256    }
257    std::string deviceId = msg.strArg_;
258    if (!session->ProcessSetUp(msg)) {
259        session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId);
260        session->RemoveRemoteDevice(deviceId);
261        session->TransferTo(session->disconnectingState_);
262    }
263}
264
265void CastSessionImpl::ConnectingState::HandleSetupSuccessMessage(const Message &msg, const MessageId &msgId,
266    sptr<CastSessionImpl> session)
267{
268    if (!session) {
269        CLOGE("Session is invalid");
270        return;
271    }
272    if (session->ProcessSetUpSuccess(msg)) {
273        session->RemoveMessage(Message(static_cast<int>(MessageId::MSG_CONNECT_TIMEOUT)));
274        CLOGI("in connecting state, defer message: %{public}d", msgId);
275        session->DeferMessage(msg);
276        session->TransferTo(session->connectedState_);
277    };
278}
279
280void CastSessionImpl::ConnectingState::HandleDisconnectMessage(const Message &msg, sptr<CastSessionImpl> session)
281{
282    if (!session) {
283        CLOGE("Session is invalid");
284        return;
285    }
286    std::string deviceId = msg.strArg_;
287    session->ProcessDisconnect(msg);
288    session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId, EventCode::ERR_CONNECTION_FAILED);
289    session->RemoveMessage(Message(static_cast<int>(MessageId::MSG_CONNECT_TIMEOUT)));
290    session->RemoveRemoteDevice(deviceId);
291    session->TransferTo(session->disconnectingState_);
292}
293
294void CastSessionImpl::ConnectingState::HandleErrorMessage(const Message &msg, sptr<CastSessionImpl> session)
295{
296    if (!session) {
297        CLOGE("Session is invalid");
298        return;
299    }
300    session->ProcessError(msg);
301    session->TransferTo(session->disconnectingState_);
302}
303
304void CastSessionImpl::ConnectingState::HandleRenderReadyMessage(const Message &msg, sptr<CastSessionImpl> session)
305{
306    if (!session) {
307        CLOGE("Session is invalid");
308        return;
309    }
310    std::string deviceId = msg.strArg_;
311    if (session->IsStreamMode()) {
312        session->RemoveMessage(Message(static_cast<int>(MessageId::MSG_CONNECT_TIMEOUT)));
313        session->ChangeDeviceState(DeviceState::STREAM, deviceId);
314        session->TransferTo(session->streamState_);
315    }
316}
317
318void CastSessionImpl::ConnectingState::HandleConnectMessage(const Message &msg, const MessageId &msgId,
319    sptr<CastSessionImpl> session)
320{
321    if (!session) {
322        CLOGE("Session is invalid");
323        return;
324    }
325    CLOGI("in connecting state, defer message: %d", msgId);
326    session->DeferMessage(msg);
327}
328
329void CastSessionImpl::ConnectedState::Enter()
330{
331    BaseState::Enter(SessionState::CONNECTED);
332
333    auto session = session_.promote();
334    if (!session) {
335        CLOGE("Session is invalid");
336        return;
337    }
338
339    if (session->property_.protocolType == ProtocolType::COOPERATION) {
340        HiSysEventWriteWrap(__func__, {
341                {"BIZ_SCENE", static_cast<int32_t>(BIZSceneType::COOPERATION)},
342                {"BIZ_STATE", static_cast<int32_t>(BIZStateType::BIZ_STATE_END)},
343                {"BIZ_STAGE", static_cast<int32_t>(BIZSceneStage::COOPERATION_CAST_SUCCESS)},
344                {"STAGE_RES", static_cast<int32_t>(StageResType::STAGE_RES_SUCCESS)},
345                {"ERROR_CODE", CAST_RADAR_SUCCESS}}, {
346                {"TO_CALL_PKG", DSOFTBUS_NAME},
347                {"LOCAL_SESS_NAME", ""},
348                {"PEER_SESS_NAME", ""},
349                {"PEER_UDID", ""}});
350    } else {
351        auto sceneType = GetBIZSceneType(static_cast<int>(session->property_.protocolType));
352        HiSysEventWriteWrap(__func__, {
353                {"BIZ_SCENE", sceneType},
354                {"BIZ_STATE", static_cast<int32_t>(BIZStateType::BIZ_STATE_END)},
355                {"BIZ_STAGE", static_cast<int32_t>(BIZSceneStage::CAST_SUCCESS)},
356                {"STAGE_RES", static_cast<int32_t>(StageResType::STAGE_RES_SUCCESS)},
357                {"ERROR_CODE", CAST_RADAR_SUCCESS}}, {
358                {"TO_CALL_PKG", DSOFTBUS_NAME},
359                {"LOCAL_SESS_NAME", ""},
360                {"PEER_SESS_NAME", ""},
361                {"PEER_UDID", ""}});
362    }
363}
364
365void CastSessionImpl::ConnectedState::Exit()
366{
367    BaseState::Exit();
368}
369
370bool CastSessionImpl::ConnectedState::HandleMessage(const Message &msg)
371{
372    auto session = session_.promote();
373    if (!session) {
374        return false;
375    }
376    BaseState::HandleMessage(msg);
377    MessageId msgId = static_cast<MessageId>(msg.what_);
378    const auto &deviceId = msg.strArg_;
379    switch (msgId) {
380        case MessageId::MSG_CONNECT:
381            // Designed for 1->N scenarios
382            session->ChangeDeviceState(DeviceState::CONNECTING, deviceId);
383            if (session->ProcessConnect(msg) >= 0) {
384                session->ChangeDeviceState(DeviceState::CONNECTED, deviceId);
385                session->ChangeDeviceState(DeviceState::PAUSED, deviceId);
386                session->TransferTo(session->pausedState_);
387            } else {
388                session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId);
389            }
390            return true;
391        case MessageId::MSG_SETUP_SUCCESS:
392            if (!session->IsStreamMode()) {
393                session->ChangeDeviceState(DeviceState::CONNECTED, deviceId);
394                session->ChangeDeviceState(DeviceState::PAUSED, deviceId);
395                session->TransferTo(session->pausedState_);
396            } else if (session->IsSink()) {
397                session->ChangeDeviceState(DeviceState::STREAM, deviceId);
398                session->TransferTo(session->streamState_);
399            }
400            return true;
401        case MessageId::MSG_DISCONNECT:
402            session->ProcessDisconnect(msg);
403            session->ChangeDeviceState(DeviceState::DISCONNECTED, deviceId);
404            session->RemoveRemoteDevice(deviceId);
405            session->TransferTo(session->disconnectingState_);
406            return true;
407        case MessageId::MSG_ERROR:
408            session->ProcessError(msg);
409            session->TransferTo(session->disconnectingState_);
410            return true;
411        case MessageId::MSG_PLAY_REQ:
412            CLOGI("in connected state, defer message: %d", msgId);
413            session->DeferMessage(msg);
414            return true;
415        default:
416            CLOGW("unsupported msg: %s, in connected state", MESSAGE_ID_STRING[msgId].c_str());
417            return false;
418    }
419}
420
421void CastSessionImpl::StreamState::Enter()
422{
423    BaseState::Enter(SessionState::STREAM);
424}
425
426void CastSessionImpl::StreamState::Exit()
427{
428    BaseState::Exit();
429}
430
431bool CastSessionImpl::StreamState::HandleMessage(const Message &msg)
432{
433    auto session = session_.promote();
434    if (!session) {
435        CLOGE("Session is invalid");
436        return false;
437    }
438    BaseState::HandleMessage(msg);
439    MessageId msgId = static_cast<MessageId>(msg.what_);
440    const auto &param = msg.strArg_;
441    auto streamManager = session->StreamManagerGetter();
442    switch (msgId) {
443        case MessageId::MSG_STREAM_RECV_ACTION_EVENT_FROM_PEERS:
444            if (msg.arg1_ == ICastStreamManager::MODULE_EVENT_ID_CHANNEL_CREATE ||
445                msg.arg1_ == ICastStreamManager::MODULE_EVENT_ID_STREAM_CHANNEL) {
446                if (session->CreateStreamChannel() == INVALID_PORT) {
447                    session->SendCastMessage(MessageId::MSG_ERROR);
448                }
449                break;
450            }
451            if (streamManager != nullptr) {
452                streamManager->ProcessActionsEvent(msg.arg1_, param);
453            } else {
454                CLOGE("streamManager is nullptr");
455            }
456            break;
457        case MessageId::MSG_STREAM_SEND_ACTION_EVENT_TO_PEERS:
458            session->SendEventChange(MODULE_ID_CAST_STREAM, msg.arg1_, param);
459            break;
460        case MessageId::MSG_PEER_RENDER_READY:
461            session->SendCastRenderReadyOption(msg.arg1_);
462            break;
463        default:
464            CLOGW("unsupported msg: %s, in stream state", MESSAGE_ID_STRING[msgId].c_str());
465            return false;
466    }
467    return true;
468}
469
470void CastSessionImpl::PausedState::Enter()
471{
472    BaseState::Enter(SessionState::PAUSED);
473}
474
475void CastSessionImpl::PausedState::Exit()
476{
477    BaseState::Exit();
478}
479
480bool CastSessionImpl::PausedState::HandleMessage(const Message &msg)
481{
482    auto session = session_.promote();
483    if (!session) {
484        CLOGE("Session is invalid");
485        return false;
486    }
487
488    BaseState::HandleMessage(msg);
489    MessageId msgId = static_cast<MessageId>(msg.what_);
490
491    switch (msgId) {
492        case MessageId::MSG_PLAY:
493        case MessageId::MSG_PLAY_REQ:
494        // vtp disconnect after paused for 30s. setup success after play request
495        case MessageId::MSG_SETUP_SUCCESS:
496            if (session->ProcessStateEvent(msgId, msg)) {
497                session->ChangeDeviceState(DeviceState::PLAYING, msg.strArg_);
498                session->TransferTo(session->playingState_);
499            }
500            break;
501        case MessageId::MSG_PROCESS_TRIGGER_REQ:
502            session->ProcessTriggerReq(msg);
503            break;
504        default:
505            CLOGW("unsupported msg: %s, in paused state", MESSAGE_ID_STRING[msgId].c_str());
506            return false;
507    }
508    return true;
509}
510
511void CastSessionImpl::PlayingState::Enter()
512{
513    BaseState::Enter(SessionState::PLAYING);
514}
515
516void CastSessionImpl::PlayingState::Exit()
517{
518    BaseState::Exit();
519}
520
521bool CastSessionImpl::PlayingState::HandleMessage(const Message &msg)
522{
523    auto session = session_.promote();
524    if (!session) {
525        CLOGE("Session is invalid");
526        return false;
527    }
528    const auto &param = msg.strArg_;
529    BaseState::HandleMessage(msg);
530    MessageId msgId = static_cast<MessageId>(msg.what_);
531    switch (msgId) {
532        case MessageId::MSG_PAUSE:
533        case MessageId::MSG_PAUSE_REQ:
534            if (session->ProcessStateEvent(msgId, msg)) {
535                session->ChangeDeviceState(DeviceState::PAUSED, msg.strArg_);
536                session->TransferTo(session->pausedState_);
537            }
538            break;
539        // Reserved MSG_PLAY and MSG_PLAY_REQ for 1->N scenarios
540        case MessageId::MSG_PLAY:
541        case MessageId::MSG_PLAY_REQ:
542            break;
543        case MessageId::MSG_UPDATE_VIDEO_SIZE:
544            session->ProcessStateEvent(MessageId::MSG_UPDATE_VIDEO_SIZE, msg);
545            break;
546        case MessageId::MSG_SET_CAST_MODE:
547            session->ProcessSetCastMode(msg);
548            break;
549        case MessageId::MSG_MIRROR_SEND_ACTION_EVENT_TO_PEERS:
550            session->SendEventChange(MODULE_ID_MEDIA, msg.arg1_, param);
551            break;
552        default:
553            CLOGW("unsupported msg: %s, in playing state", MESSAGE_ID_STRING[msgId].c_str());
554            return false;
555    }
556    return true;
557}
558
559void CastSessionImpl::DisconnectingState::Enter()
560{
561    auto session = session_.promote();
562    if (!session) {
563        CLOGE("Session is invalid");
564        return;
565    }
566
567    BaseState::Enter(SessionState::DISCONNECTING);
568    session->TransferTo(session->disconnectedState_);
569}
570
571void CastSessionImpl::DisconnectingState::Exit()
572{
573    BaseState::Exit();
574}
575
576bool CastSessionImpl::DisconnectingState::HandleMessage(const Message &msg)
577{
578    auto session = session_.promote();
579    if (!session) {
580        CLOGE("Session is invalid");
581        return false;
582    }
583
584    BaseState::HandleMessage(msg);
585    MessageId msgId = static_cast<MessageId>(msg.what_);
586
587    switch (msgId) {
588        case MessageId::MSG_CONNECT:
589            CLOGI("in connecting state, defer message: %d", msgId);
590            session->DeferMessage(msg);
591            break;
592        default:
593            CLOGW("unsupported msg: %s, in disconnecting state", MESSAGE_ID_STRING[msgId].c_str());
594            return false;
595    }
596    return true;
597}
598} // namespace CastEngineService
599} // namespace CastEngine
600} // namespace OHOS