1fa7767c5Sopenharmony_ci/* 2fa7767c5Sopenharmony_ci * Copyright (c) 2021-2021 Huawei Device Co., Ltd. 3fa7767c5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fa7767c5Sopenharmony_ci * you may not use this file except in compliance with the License. 5fa7767c5Sopenharmony_ci * You may obtain a copy of the License at 6fa7767c5Sopenharmony_ci * 7fa7767c5Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fa7767c5Sopenharmony_ci * 9fa7767c5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fa7767c5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fa7767c5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fa7767c5Sopenharmony_ci * See the License for the specific language governing permissions and 13fa7767c5Sopenharmony_ci * limitations under the License. 14fa7767c5Sopenharmony_ci */ 15fa7767c5Sopenharmony_ci 16fa7767c5Sopenharmony_ci#define HST_LOG_TAG "StateMachine" 17fa7767c5Sopenharmony_ci 18fa7767c5Sopenharmony_ci#include "state_machine.h" 19fa7767c5Sopenharmony_ci#include "eos_state.h" 20fa7767c5Sopenharmony_ci#include "foundation/osal/utils/util.h" 21fa7767c5Sopenharmony_ci#include "foundation/utils/steady_clock.h" 22fa7767c5Sopenharmony_ci#include "idle_state.h" 23fa7767c5Sopenharmony_ci#include "init_state.h" 24fa7767c5Sopenharmony_ci#include "pause_state.h" 25fa7767c5Sopenharmony_ci#include "playing_state.h" 26fa7767c5Sopenharmony_ci#include "preparing_state.h" 27fa7767c5Sopenharmony_ci#include "ready_state.h" 28fa7767c5Sopenharmony_ci#include "stopped_state.h" 29fa7767c5Sopenharmony_ci 30fa7767c5Sopenharmony_cinamespace OHOS { 31fa7767c5Sopenharmony_cinamespace Media { 32fa7767c5Sopenharmony_ciStateMachine::StateMachine(PlayExecutor& executor) 33fa7767c5Sopenharmony_ci : Task("StateMachine"), 34fa7767c5Sopenharmony_ci intentSync_("fsmSync"), 35fa7767c5Sopenharmony_ci curState_(std::make_shared<IdleState>(StateId::IDLE, executor)), 36fa7767c5Sopenharmony_ci jobs_("StateMachineJobQue") 37fa7767c5Sopenharmony_ci{ 38fa7767c5Sopenharmony_ci AddState(curState_); 39fa7767c5Sopenharmony_ci AddState(std::make_shared<InitState>(StateId::INIT, executor)); 40fa7767c5Sopenharmony_ci AddState(std::make_shared<PreparingState>(StateId::PREPARING, executor)); 41fa7767c5Sopenharmony_ci AddState(std::make_shared<ReadyState>(StateId::READY, executor)); 42fa7767c5Sopenharmony_ci AddState(std::make_shared<PlayingState>(StateId::PLAYING, executor)); 43fa7767c5Sopenharmony_ci AddState(std::make_shared<PauseState>(StateId::PAUSE, executor)); 44fa7767c5Sopenharmony_ci AddState(std::make_shared<StoppedState>(StateId::STOPPED, executor)); 45fa7767c5Sopenharmony_ci AddState(std::make_shared<EosState>(StateId::EOS, executor)); 46fa7767c5Sopenharmony_ci} 47fa7767c5Sopenharmony_ci 48fa7767c5Sopenharmony_civoid StateMachine::Stop() 49fa7767c5Sopenharmony_ci{ 50fa7767c5Sopenharmony_ci MEDIA_LOG_I("StateMachine stop called."); 51fa7767c5Sopenharmony_ci while (!jobs_.Empty()) { 52fa7767c5Sopenharmony_ci OSAL::SleepFor(10); // 10 53fa7767c5Sopenharmony_ci } 54fa7767c5Sopenharmony_ci jobs_.SetActive(false); 55fa7767c5Sopenharmony_ci Task::Stop(); 56fa7767c5Sopenharmony_ci} 57fa7767c5Sopenharmony_ci 58fa7767c5Sopenharmony_civoid StateMachine::SetStateCallback(StateChangeCallback* callback) 59fa7767c5Sopenharmony_ci{ 60fa7767c5Sopenharmony_ci callback_ = callback; 61fa7767c5Sopenharmony_ci} 62fa7767c5Sopenharmony_ci 63fa7767c5Sopenharmony_ciconst std::string& StateMachine::GetCurrentState() const 64fa7767c5Sopenharmony_ci{ 65fa7767c5Sopenharmony_ci return curState_->GetName(); 66fa7767c5Sopenharmony_ci} 67fa7767c5Sopenharmony_ci 68fa7767c5Sopenharmony_ciStateId StateMachine::GetCurrentStateId() const 69fa7767c5Sopenharmony_ci{ 70fa7767c5Sopenharmony_ci return curState_->GetStateId(); 71fa7767c5Sopenharmony_ci} 72fa7767c5Sopenharmony_ci 73fa7767c5Sopenharmony_ciErrorCode StateMachine::SendEvent(Intent intent, const Plugin::Any& param) const 74fa7767c5Sopenharmony_ci{ 75fa7767c5Sopenharmony_ci return const_cast<StateMachine*>(this)->SendEvent(intent, param); 76fa7767c5Sopenharmony_ci} 77fa7767c5Sopenharmony_ci 78fa7767c5Sopenharmony_ciErrorCode StateMachine::SendEvent(Intent intent, const Plugin::Any& param) 79fa7767c5Sopenharmony_ci{ 80fa7767c5Sopenharmony_ci constexpr int timeoutMs = 30000; 81fa7767c5Sopenharmony_ci ErrorCode errorCode = ErrorCode::ERROR_TIMED_OUT; 82fa7767c5Sopenharmony_ci if (!intentSync_.WaitFor( 83fa7767c5Sopenharmony_ci intent, [this, intent, param] { return SendEventAsync(intent, param) == ErrorCode::SUCCESS; }, 84fa7767c5Sopenharmony_ci timeoutMs, errorCode)) { 85fa7767c5Sopenharmony_ci MEDIA_LOG_E("SendEvent timeout, intent: " PUBLIC_LOG_S " - " PUBLIC_LOG_D32, 86fa7767c5Sopenharmony_ci State::GetIntentName(intent), static_cast<int>(intent)); 87fa7767c5Sopenharmony_ci } 88fa7767c5Sopenharmony_ci return errorCode; 89fa7767c5Sopenharmony_ci} 90fa7767c5Sopenharmony_ci 91fa7767c5Sopenharmony_ciErrorCode StateMachine::SendEventAsync(Intent intent, const Plugin::Any& param) const 92fa7767c5Sopenharmony_ci{ 93fa7767c5Sopenharmony_ci return const_cast<StateMachine*>(this)->SendEventAsync(intent, param); 94fa7767c5Sopenharmony_ci} 95fa7767c5Sopenharmony_ci 96fa7767c5Sopenharmony_ciErrorCode StateMachine::SendEventAsync(Intent intent, const Plugin::Any& param) 97fa7767c5Sopenharmony_ci{ 98fa7767c5Sopenharmony_ci MEDIA_LOG_D("SendEventAsync, intent: " PUBLIC_LOG_S " - " PUBLIC_LOG_D32, 99fa7767c5Sopenharmony_ci State::GetIntentName(intent), static_cast<int>(intent)); 100fa7767c5Sopenharmony_ci if (jobs_.Push([this, intent, param]() -> Action { return ProcessIntent(intent, param); })) { 101fa7767c5Sopenharmony_ci return ErrorCode::SUCCESS; 102fa7767c5Sopenharmony_ci } 103fa7767c5Sopenharmony_ci return ErrorCode::ERROR_UNKNOWN; 104fa7767c5Sopenharmony_ci} 105fa7767c5Sopenharmony_ci 106fa7767c5Sopenharmony_ciAction StateMachine::ProcessIntent(Intent intent, const Plugin::Any& param) 107fa7767c5Sopenharmony_ci{ 108fa7767c5Sopenharmony_ci MEDIA_LOG_D("ProcessIntent, curState: " PUBLIC_LOG_S ", intent: " PUBLIC_LOG_S, 109fa7767c5Sopenharmony_ci curState_->GetName().c_str(), State::GetIntentName(intent)); 110fa7767c5Sopenharmony_ci PROFILE_BEGIN("ProcessIntent, curState: " PUBLIC_LOG_S ", intent: " PUBLIC_LOG_S, 111fa7767c5Sopenharmony_ci curState_->GetName().c_str(), State::GetIntentName(intent)); 112fa7767c5Sopenharmony_ci OSAL::ScopedLock lock(mutex_); 113fa7767c5Sopenharmony_ci lastIntent = intent; 114fa7767c5Sopenharmony_ci ErrorCode rtv = ErrorCode::SUCCESS; 115fa7767c5Sopenharmony_ci Action nextAction = Action::ACTION_BUTT; 116fa7767c5Sopenharmony_ci std::tie(rtv, nextAction) = curState_->Execute(intent, param); 117fa7767c5Sopenharmony_ci if (nextAction != Action::ACTION_BUTT) { 118fa7767c5Sopenharmony_ci if (rtv == ErrorCode::SUCCESS) { 119fa7767c5Sopenharmony_ci rtv = ProcAction(nextAction); 120fa7767c5Sopenharmony_ci } else { 121fa7767c5Sopenharmony_ci (void)ProcAction(nextAction); 122fa7767c5Sopenharmony_ci } 123fa7767c5Sopenharmony_ci } 124fa7767c5Sopenharmony_ci OnIntentExecuted(intent, nextAction, rtv); 125fa7767c5Sopenharmony_ci PROFILE_END("ProcessIntent, curState: " PUBLIC_LOG_S ", intent: " PUBLIC_LOG_S, 126fa7767c5Sopenharmony_ci curState_->GetName().c_str(), State::GetIntentName(intent)); 127fa7767c5Sopenharmony_ci return (rtv == ErrorCode::SUCCESS) ? nextAction : Action::ACTION_BUTT; 128fa7767c5Sopenharmony_ci} 129fa7767c5Sopenharmony_ci 130fa7767c5Sopenharmony_civoid StateMachine::DoTask() 131fa7767c5Sopenharmony_ci{ 132fa7767c5Sopenharmony_ci#ifdef UNIT_TEST 133fa7767c5Sopenharmony_ci constexpr int timeoutMs = 500; 134fa7767c5Sopenharmony_ci auto job = jobs_.Pop(timeoutMs); 135fa7767c5Sopenharmony_ci#else 136fa7767c5Sopenharmony_ci auto job = jobs_.Pop(); 137fa7767c5Sopenharmony_ci#endif 138fa7767c5Sopenharmony_ci if (!job) { 139fa7767c5Sopenharmony_ci return; 140fa7767c5Sopenharmony_ci } 141fa7767c5Sopenharmony_ci auto action = job(); 142fa7767c5Sopenharmony_ci switch (action) { 143fa7767c5Sopenharmony_ci case Action::ACTION_PENDING: 144fa7767c5Sopenharmony_ci pendingJobs_.push(job); 145fa7767c5Sopenharmony_ci break; 146fa7767c5Sopenharmony_ci case Action::TRANS_TO_IDLE: 147fa7767c5Sopenharmony_ci case Action::TRANS_TO_INIT: 148fa7767c5Sopenharmony_ci case Action::TRANS_TO_PREPARING: 149fa7767c5Sopenharmony_ci case Action::TRANS_TO_READY: 150fa7767c5Sopenharmony_ci case Action::TRANS_TO_PLAYING: 151fa7767c5Sopenharmony_ci case Action::TRANS_TO_PAUSE: 152fa7767c5Sopenharmony_ci case Action::TRANS_TO_STOPPED: 153fa7767c5Sopenharmony_ci case Action::TRANS_TO_EOS: { 154fa7767c5Sopenharmony_ci if (!pendingJobs_.empty()) { 155fa7767c5Sopenharmony_ci job = pendingJobs_.front(); 156fa7767c5Sopenharmony_ci pendingJobs_.pop(); 157fa7767c5Sopenharmony_ci action = job(); 158fa7767c5Sopenharmony_ci if (action == Action::ACTION_PENDING) { 159fa7767c5Sopenharmony_ci pendingJobs_.push(job); 160fa7767c5Sopenharmony_ci } 161fa7767c5Sopenharmony_ci } 162fa7767c5Sopenharmony_ci break; 163fa7767c5Sopenharmony_ci } 164fa7767c5Sopenharmony_ci case Action::ACTION_BUTT: 165fa7767c5Sopenharmony_ci // fall through 166fa7767c5Sopenharmony_ci default: 167fa7767c5Sopenharmony_ci break; 168fa7767c5Sopenharmony_ci } 169fa7767c5Sopenharmony_ci} 170fa7767c5Sopenharmony_ci 171fa7767c5Sopenharmony_civoid StateMachine::AddState(const std::shared_ptr<State>& state) 172fa7767c5Sopenharmony_ci{ 173fa7767c5Sopenharmony_ci states_[state->GetStateId()] = state; 174fa7767c5Sopenharmony_ci} 175fa7767c5Sopenharmony_ci 176fa7767c5Sopenharmony_ciErrorCode StateMachine::ProcAction(Action nextAction) 177fa7767c5Sopenharmony_ci{ 178fa7767c5Sopenharmony_ci std::shared_ptr<State> nextState = nullptr; 179fa7767c5Sopenharmony_ci switch (nextAction) { 180fa7767c5Sopenharmony_ci case Action::TRANS_TO_IDLE: 181fa7767c5Sopenharmony_ci nextState = states_[StateId::IDLE]; 182fa7767c5Sopenharmony_ci break; 183fa7767c5Sopenharmony_ci case Action::TRANS_TO_INIT: 184fa7767c5Sopenharmony_ci nextState = states_[StateId::INIT]; 185fa7767c5Sopenharmony_ci break; 186fa7767c5Sopenharmony_ci case Action::TRANS_TO_PREPARING: 187fa7767c5Sopenharmony_ci nextState = states_[StateId::PREPARING]; 188fa7767c5Sopenharmony_ci break; 189fa7767c5Sopenharmony_ci case Action::TRANS_TO_READY: 190fa7767c5Sopenharmony_ci nextState = states_[StateId::READY]; 191fa7767c5Sopenharmony_ci break; 192fa7767c5Sopenharmony_ci case Action::TRANS_TO_PLAYING: 193fa7767c5Sopenharmony_ci nextState = states_[StateId::PLAYING]; 194fa7767c5Sopenharmony_ci break; 195fa7767c5Sopenharmony_ci case Action::TRANS_TO_PAUSE: 196fa7767c5Sopenharmony_ci nextState = states_[StateId::PAUSE]; 197fa7767c5Sopenharmony_ci break; 198fa7767c5Sopenharmony_ci case Action::TRANS_TO_STOPPED: 199fa7767c5Sopenharmony_ci nextState = states_[StateId::STOPPED]; 200fa7767c5Sopenharmony_ci break; 201fa7767c5Sopenharmony_ci case Action::TRANS_TO_EOS: 202fa7767c5Sopenharmony_ci nextState = states_[StateId::EOS]; 203fa7767c5Sopenharmony_ci break; 204fa7767c5Sopenharmony_ci default: 205fa7767c5Sopenharmony_ci break; 206fa7767c5Sopenharmony_ci } 207fa7767c5Sopenharmony_ci ErrorCode ret = ErrorCode::SUCCESS; 208fa7767c5Sopenharmony_ci if (nextState) { 209fa7767c5Sopenharmony_ci ret = TransitionTo(nextState); 210fa7767c5Sopenharmony_ci } 211fa7767c5Sopenharmony_ci return ret; 212fa7767c5Sopenharmony_ci} 213fa7767c5Sopenharmony_ci 214fa7767c5Sopenharmony_ciErrorCode StateMachine::TransitionTo(const std::shared_ptr<State>& state) 215fa7767c5Sopenharmony_ci{ 216fa7767c5Sopenharmony_ci if (state == nullptr) { 217fa7767c5Sopenharmony_ci MEDIA_LOG_E("TransitionTo, state is nullptr"); 218fa7767c5Sopenharmony_ci return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; 219fa7767c5Sopenharmony_ci } 220fa7767c5Sopenharmony_ci ErrorCode rtv = ErrorCode::SUCCESS; 221fa7767c5Sopenharmony_ci if (state != curState_) { 222fa7767c5Sopenharmony_ci curState_->Exit(); 223fa7767c5Sopenharmony_ci curState_ = state; 224fa7767c5Sopenharmony_ci Action nextAction; 225fa7767c5Sopenharmony_ci std::tie(rtv, nextAction) = curState_->Enter(lastIntent); 226fa7767c5Sopenharmony_ci if (rtv == ErrorCode::SUCCESS) { 227fa7767c5Sopenharmony_ci rtv = ProcAction(nextAction); 228fa7767c5Sopenharmony_ci } 229fa7767c5Sopenharmony_ci if (callback_) { 230fa7767c5Sopenharmony_ci callback_->OnStateChanged(curState_->GetStateId()); 231fa7767c5Sopenharmony_ci } 232fa7767c5Sopenharmony_ci } 233fa7767c5Sopenharmony_ci return rtv; 234fa7767c5Sopenharmony_ci} 235fa7767c5Sopenharmony_ci 236fa7767c5Sopenharmony_civoid StateMachine::OnIntentExecuted(Intent intent, Action action, ErrorCode result) 237fa7767c5Sopenharmony_ci{ 238fa7767c5Sopenharmony_ci MEDIA_LOG_D("OnIntentExecuted, curState: " PUBLIC_LOG_S ", intent: " PUBLIC_LOG_S ", action: " PUBLIC_LOG_S 239fa7767c5Sopenharmony_ci ", result: " PUBLIC_LOG_S, curState_->GetName().c_str(), 240fa7767c5Sopenharmony_ci State::GetIntentName(intent), State::GetActionName(action), GetErrorName(result)); 241fa7767c5Sopenharmony_ci if (action == Action::ACTION_PENDING) { 242fa7767c5Sopenharmony_ci return; 243fa7767c5Sopenharmony_ci } 244fa7767c5Sopenharmony_ci if (result == ErrorCode::ERROR_NO_NOTIFY) { 245fa7767c5Sopenharmony_ci return; 246fa7767c5Sopenharmony_ci } 247fa7767c5Sopenharmony_ci if (intent == Intent::NOTIFY_READY && action == Action::TRANS_TO_PLAYING) { 248fa7767c5Sopenharmony_ci intentSync_.Notify(Intent::PLAY, result); 249fa7767c5Sopenharmony_ci } else { 250fa7767c5Sopenharmony_ci intentSync_.Notify(intent, result); 251fa7767c5Sopenharmony_ci } 252fa7767c5Sopenharmony_ci} 253fa7767c5Sopenharmony_ci 254fa7767c5Sopenharmony_civoid StateMachine::Notify(Intent intent, ErrorCode code) 255fa7767c5Sopenharmony_ci{ 256fa7767c5Sopenharmony_ci intentSync_.Notify(intent, code); 257fa7767c5Sopenharmony_ci} 258fa7767c5Sopenharmony_ci} // namespace Media 259fa7767c5Sopenharmony_ci} // namespace OHOS