1 /*
2  * Copyright (c) 2020-2021 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  */
15 
16 #include "liteplayer_state_machine.h"
17 #include "liteplayer.h"
18 #include "liteplayer_comm.h"
19 #include "hi_liteplayer_err.h"
20 
21 namespace OHOS {
22 namespace Media {
23 
24 namespace {
25     /*****************************************************************************
26     status table of operation, false is not support
27     *******************************************************************/
28     const bool LITEPLAY_STATE[PLAYERCONTROL_MSG_BUTT][PLAY_STATUS_BUTT] = {
29         /* idle,    init,     prepare   play,     tplay,    pause,    err */
30         { false, false, true,  false, false, false, false }, /* setMedia */
31         { true,  true,  true,  true,  true,  true,  true },  /* regCallbk */
32         { true,  true,  false, false, false, false, false }, /* setsrc_fd */
33         { true,  true,  false, false, false, false, false }, /* setsrc_uri */
34         { true,  true,  false, false, false, false, false }, /* setsrc_stream */
35         { false, true,  true,  false, false, false, false }, /* prepare */
36         { false, false, true,  true,  true,  true,  false }, /* play */
37         { false, false, true,  true,  true,  true,  false }, /* seek */
38         { false, false, false, true,  false, true,  false }, /* pause */
39         { false, false, false, true,  true,  false, false }, /* tplay */
40         { true,  true,  true,  true,  true,  true,  true },  /* stop */
41         { false, false, true,  true,  true,  true,  false }, /* getInfo */
42         { true,  false, false, true,  true,  true,  false }, /* handledata */
43         { true,  true,  true,  true,  true,  true,  true },  /* Error */
44         { false, true,  true,  true,  true,  true,  false },  /* setVolume */
45         { true,  true,  true,  true,  true,  true,  true },  /* invoke */
46         { true,  true,  true,  false, false, false, false },  /* set audio stream type */
47     };
48 
49     struct PlayerControlStatusMap {
50         PlayerStatus state;
51         const std::string stateName;
52     };
53 
54     const PlayerControlStatusMap LITEPLAY_STATEMAP[PLAY_STATUS_BUTT] = {
55         { PLAY_STATUS_IDLE,     "idle" },
56         { PLAY_STATUS_INIT,     "init" },
57         { PLAY_STATUS_PREPARED, "prepare" },
58         { PLAY_STATUS_PLAY,     "play" },
59         { PLAY_STATUS_TPLAY,    "tplay" },
60         { PLAY_STATUS_PAUSE,    "pause" },
61         { PLAY_STATUS_ERR,      "error" },
62     };
63 }
64 
65 #define CHECK_NULL_RETURN(value, ret, printfString) \
66 do { \
67     if (value == nullptr) { \
68         MEDIA_ERR_LOG( "playerStateMachine %s \n", printfString ? printfString : " "); \
69         return ret; \
70     } \
71 } while (0)
72 
StateConvert2Enum(const std::string stateName)73 PlayerStatus StateConvert2Enum(const std::string stateName)
74 {
75     bool isFound = false;
76     uint32_t i = 0;
77 
78     for (; i < PLAY_STATUS_BUTT; i++) {
79         if (stateName == LITEPLAY_STATEMAP[i].stateName) {
80             isFound = true;
81             break;
82         }
83     }
84     if (isFound == false) {
85         MEDIA_ERR_LOG("could not find respond state :%s", stateName.c_str());
86         return PLAY_STATUS_BUTT;
87     }
88     return LITEPLAY_STATEMAP[i].state;
89 }
90 
StateEnum2Name(PlayerStatus state)91 static std::string StateEnum2Name(PlayerStatus state)
92 {
93     return LITEPLAY_STATEMAP[state].stateName;
94 }
95 
~PlayerControlState()96 PlayerControlState::~PlayerControlState()
97 {
98 }
99 
Enter()100 int PlayerControlState::Enter()
101 {
102     PlayerStatus playerStatus = StateConvert2Enum(Name());
103     CHECK_NULL_RETURN(playerControlHandle_, HI_ERR_PLAYERCONTROL_NULL_PTR, "handle null");
104     playerControlHandle_->StateChangeCallback(playerStatus);
105     MEDIA_DEBUG_LOG( "enter state: %s\n", Name().c_str());
106     return HI_SUCCESS;
107 }
108 
Exit()109 int PlayerControlState::Exit()
110 {
111     MEDIA_DEBUG_LOG( "exit state: %s", Name().c_str());
112     return HI_SUCCESS;
113 }
114 
FindTransition(int event)115 HiState *PlayerControlState::FindTransition(int event)
116 {
117     HiState *dstState = HiState::FindTransition(event);
118     return dstState;
119 }
120 
HandleMessage(const MsgInfo & msgInfo)121 int PlayerControlState::HandleMessage(const MsgInfo& msgInfo)
122 {
123     int32_t ret = HI_SUCCESS;
124 
125     CHECK_NULL_RETURN(curState_, HI_ERR_PLAYERCONTROL_NULL_PTR, "curState null");
126     if (!curState_->EventValidAtCurState((PlayerControlMsgType)msgInfo.what)) {
127         MEDIA_ERR_LOG( "invalid event :%d at current state: %s", msgInfo.what,
128                       Name().c_str());
129         return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;
130     }
131     CHECK_NULL_RETURN(playerControlHandle_, HI_ERR_PLAYERCONTROL_NULL_PTR, "handle null");
132     switch (msgInfo.what) {
133         case PLAYERCONTROL_MSG_REGCALLBACK:
134             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
135             ret = playerControlHandle_->DoRegCallback(*reinterpret_cast<PlayerCtrlCallbackParam *>(msgInfo.msgData));
136             break;
137         case PLAYERCONTROL_MSG_SET_DATASOURCE_URI:
138             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
139             ret = playerControlHandle_->DoSetDataSource(reinterpret_cast<const char *>(msgInfo.msgData));
140             break;
141         case PLAYERCONTROL_MSG_SET_DATASOURCE_FD:
142             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
143             ret = playerControlHandle_->DoSetDataSource(*reinterpret_cast<const int *>(msgInfo.msgData));
144             break;
145         case PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM:
146             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
147             ret = playerControlHandle_->DoSetDataSource(*reinterpret_cast<BufferStream *>(msgInfo.msgData));
148             break;
149         case PLAYERCONTROL_MSG_SETATTR:
150             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
151             ret = playerControlHandle_->DoSetMedia(*reinterpret_cast<PlayerControlStreamAttr *>(msgInfo.msgData));
152             break;
153         case PLAYERCONTROL_MSG_PAUSE:
154             ret = playerControlHandle_->DoPause();
155             break;
156         case PLAYERCONTROL_MSG_TPLAY:
157             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
158             ret = playerControlHandle_->DoTPlay(*reinterpret_cast<TplayAttr *>(msgInfo.msgData));
159             break;
160         case PLAYERCONTROL_MSG_PREPARE:
161             ret = playerControlHandle_->DoPrepare();
162             break;
163         case PLAYERCONTROL_MSG_PLAY:
164             ret = playerControlHandle_->DoPlay();
165             break;
166         case PLAYERCONTROL_MSG_SET_VOLUME:
167             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
168             ret = playerControlHandle_->DoSetVolume(*reinterpret_cast<VolumeAttr *>(msgInfo.msgData));
169             break;
170         case PLAYERCONTROL_MSG_HANDLEDATA:
171             ret = HI_SUCCESS;
172             break;
173         case PLAYERCONTROL_MSG_STOP:
174             ret = playerControlHandle_->DoStop();
175             break;
176         case PLAYERCONTROL_MSG_SEEK:
177             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
178             ret = playerControlHandle_->DoSeek(*reinterpret_cast<int64_t *>(msgInfo.msgData));
179             break;
180         case PLAYERCONTROL_MSG_GETFILEINFO:
181             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
182             ret = playerControlHandle_->DoGetFileInfo(*reinterpret_cast<FormatFileInfo *>(msgInfo.msgData));
183             break;
184         case PLAYERCONTROL_MSG_INVOKE:
185             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
186             ret = playerControlHandle_->DoInvoke(*reinterpret_cast<InvokeParameter *>(msgInfo.msgData));
187             break;
188         case PLAYERCONTROL_MSG_SET_AUDIOSTREAM_TYPE:
189             CHECK_NULL_RETURN(msgInfo.msgData, HI_ERR_PLAYERCONTROL_NULL_PTR, "msgData null");
190             ret = playerControlHandle_->DoSetAudioStreamType(*reinterpret_cast<int32_t *>(msgInfo.msgData));
191             break;
192         default:
193             ret = HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;
194             break;
195     }
196 
197     return ret;
198 }
199 
OnEventHandled(const HiStateMachine & curState,int event,int result)200 void PlayerControlSMObserver::OnEventHandled(const HiStateMachine &curState, int event, int result)
201 {
202     (void)curState;
203     if ((result == HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION) && (event == PLAYERCONTROL_MSG_SEEK) &&
204         (playerControlHandle_ != nullptr)) {
205         playerControlHandle_->NotifyError(PLAYERCONTROL_ERROR_ILLEGAL_STATEACTION);
206     }
207 }
208 
~PlayerControlSMObserver()209 PlayerControlSMObserver::~PlayerControlSMObserver()
210 {
211 }
212 
PlayerControlStateMachine(PlayerControlHandle & handle)213 PlayerControlStateMachine::PlayerControlStateMachine(PlayerControlHandle& handle)
214     : HiStateMachine(), playerControlHandle_(&handle), stateIdle_(nullptr), stateInit_(nullptr),
215       statePrepare_(nullptr), statePlay_(nullptr), stateTPlay_(nullptr),
216       statePause_(nullptr), stateError_(nullptr)
217 {
218 }
219 
~PlayerControlStateMachine()220 PlayerControlStateMachine::~PlayerControlStateMachine()
221 {
222     (void)Deinit();
223 }
224 
CreateStates()225 int32_t PlayerControlStateMachine::CreateStates()
226 {
227     CHECK_NULL_RETURN(playerControlHandle_, HI_ERR_PLAYERCONTROL_NULL_PTR, "handle null");
228     stateIdle_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
229         StateEnum2Name(PLAY_STATUS_IDLE));
230     if (stateIdle_ == nullptr) {
231         MEDIA_ERR_LOG( "new stateIdle_ failed");
232         return HI_ERR_PLAYERCONTROL_MEM_MALLOC;
233     }
234     stateInit_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
235         StateEnum2Name(PLAY_STATUS_INIT));
236     if (stateInit_ == nullptr) {
237         MEDIA_ERR_LOG( "new stateInit_ failed");
238         goto DESTROY;
239     }
240     statePrepare_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
241         StateEnum2Name(PLAY_STATUS_PREPARED));
242     if (statePrepare_ == nullptr) {
243         MEDIA_ERR_LOG( "new statePrepare_ failed");
244         goto DESTROY;
245     }
246     statePlay_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
247         StateEnum2Name(PLAY_STATUS_PLAY));
248     if (statePlay_ == nullptr) {
249         MEDIA_ERR_LOG( "new statePlay_ failed");
250         goto DESTROY;
251     }
252     stateTPlay_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
253         StateEnum2Name(PLAY_STATUS_TPLAY));
254     if (stateTPlay_ == nullptr) {
255         MEDIA_ERR_LOG( "new stateTPlay_ failed");
256         goto DESTROY;
257     }
258     statePause_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
259         StateEnum2Name(PLAY_STATUS_PAUSE));
260     if (statePause_ == nullptr) {
261         MEDIA_ERR_LOG( "new statePause_ failed");
262         goto DESTROY;
263     }
264     stateError_ = new(std::nothrow) PlayerControlState(*playerControlHandle_, *this,
265         StateEnum2Name(PLAY_STATUS_ERR));
266     if (stateError_ == nullptr) {
267         MEDIA_ERR_LOG( "new stateError_ failed");
268         goto DESTROY;
269     }
270     return HI_SUCCESS;
271 DESTROY:
272     DestroyStates();
273     return HI_ERR_PLAYERCONTROL_MEM_MALLOC;
274 }
275 
DestroyStates()276 void PlayerControlStateMachine::DestroyStates()
277 {
278     if (stateIdle_ != nullptr) {
279         delete stateIdle_;
280         stateIdle_ = nullptr;
281     }
282     if (stateInit_ != nullptr) {
283         delete stateInit_;
284         stateInit_ = nullptr;
285     }
286     if (statePrepare_ != nullptr) {
287         delete statePrepare_;
288         statePrepare_ = nullptr;
289     }
290     if (statePlay_ != nullptr) {
291         delete statePlay_;
292         statePlay_ = nullptr;
293     }
294     if (stateTPlay_ != nullptr) {
295         delete stateTPlay_;
296         stateTPlay_ = nullptr;
297     }
298     if (statePause_ != nullptr) {
299         delete statePause_;
300         statePause_ = nullptr;
301     }
302     if (stateError_ != nullptr) {
303         delete stateError_;
304         stateError_ = nullptr;
305     }
306 }
307 
Init(uint32_t maxQueueSize,uint32_t maxMsgPayloadSize)308 int32_t PlayerControlStateMachine::Init(uint32_t maxQueueSize, uint32_t maxMsgPayloadSize)
309 {
310     const std::string playerControlSmName = "playerCtrl_sm";
311     int32_t ret = HiStateMachine::Init(maxQueueSize, maxMsgPayloadSize, playerControlSmName);
312     if (ret != HI_SUCCESS) {
313         printf("HiStateMachine::Init failed");
314         return ret;
315     }
316     ret = CreateStates();
317     if (ret != HI_SUCCESS) {
318         MEDIA_ERR_LOG( "createStates failed");
319         return ret;
320     }
321     stateIdle_->AddTransition(PLAYERCONTROL_MSG_SET_DATASOURCE_FD, *stateInit_);
322     stateIdle_->AddTransition(PLAYERCONTROL_MSG_SET_DATASOURCE_URI, *stateInit_);
323     stateIdle_->AddTransition(PLAYERCONTROL_MSG_SET_DATASOURCE_STREAM, *stateInit_);
324     stateIdle_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
325     stateInit_->AddTransition(PLAYERCONTROL_MSG_PREPARE, *statePrepare_);
326     stateInit_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
327     stateInit_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
328     statePrepare_->AddTransition(PLAYERCONTROL_MSG_PLAY, *statePlay_);
329     statePrepare_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
330     statePrepare_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
331     statePlay_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
332     statePlay_->AddTransition(PLAYERCONTROL_MSG_TPLAY, *stateTPlay_);
333     statePlay_->AddTransition(PLAYERCONTROL_MSG_PAUSE, *statePause_);
334     statePlay_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
335     stateTPlay_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
336     stateTPlay_->AddTransition(PLAYERCONTROL_MSG_PLAY, *statePlay_);
337     stateTPlay_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
338     statePause_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
339     statePause_->AddTransition(PLAYERCONTROL_MSG_PLAY, *statePlay_);
340     statePause_->AddTransition(PLAYERCONTROL_MSG_ERROR, *stateError_);
341     stateError_->AddTransition(PLAYERCONTROL_MSG_STOP, *stateIdle_);
342     (void)AddState(*stateIdle_);
343     (void)AddState(*stateInit_);
344     (void)AddState(*statePrepare_);
345     (void)AddState(*statePlay_);
346     (void)AddState(*stateTPlay_);
347     (void)AddState(*statePause_);
348     (void)AddState(*stateError_);
349     (void)SetInitialState(*stateIdle_);
350     return HI_SUCCESS;
351 }
352 
Deinit()353 int32_t PlayerControlStateMachine::Deinit()
354 {
355     DestroyStates();
356     int32_t ret = HiStateMachine::Deinit();
357     if (ret != HI_SUCCESS) {
358         MEDIA_ERR_LOG( "HiStateMachine::Deinit failed");
359         return ret;
360     }
361     return HI_SUCCESS;
362 }
363 
GetCurState()364 PlayerStatus PlayerControlStateMachine::GetCurState()
365 {
366     const HiState* curState = CurrentState();
367     return StateConvert2Enum(curState->Name());
368 }
369 
EventValidAtCurState(PlayerControlMsgType type)370 bool PlayerControlStateMachine::EventValidAtCurState(PlayerControlMsgType type)
371 {
372     if (type < PLAYERCONTROL_MSG_SETATTR || type >= PLAYERCONTROL_MSG_BUTT) {
373         MEDIA_ERR_LOG( "EventValidAtCurState MSG type not support %d", type);
374         return false;
375     }
376     return LITEPLAY_STATE[type][GetCurState()];
377 }
378 }
379 }
380