1 /*
2  * Copyright (C) 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 "player_server_task_mgr.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19 #include "qos.h"
20 
21 using namespace OHOS::QOS;
22 
23 namespace {
24     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "PlayerServerTaskMgr" };
25 }
26 
27 namespace OHOS {
28 namespace Media {
PlayerServerTaskMgr()29 PlayerServerTaskMgr::PlayerServerTaskMgr()
30 {
31     MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
32 }
33 
~PlayerServerTaskMgr()34 PlayerServerTaskMgr::~PlayerServerTaskMgr()
35 {
36     MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
37     (void)Reset();
38 }
39 
Init()40 int32_t PlayerServerTaskMgr::Init()
41 {
42     std::unique_lock<std::mutex> lock(mutex_);
43     if (isInited_) {
44         return MSERR_OK;
45     }
46 
47     taskThread_ = std::make_unique<TaskQueue>("PlayerEngine");
48     int32_t ret = taskThread_->Start();
49     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "task thread start failed");
50     isInited_ = true;
51 
52     return MSERR_OK;
53 }
54 
EnqueueTask(const std::shared_ptr<ITaskHandler> & task,PlayerServerTaskType type,const std::string & taskName)55 int32_t PlayerServerTaskMgr::EnqueueTask(const std::shared_ptr<ITaskHandler> &task, PlayerServerTaskType type,
56     const std::string &taskName)
57 {
58     (void)taskThread_->EnqueueTask(task);
59     currTwoPhaseTask_ = task;
60     currTwoPhaseType_ = type;
61     currTwoPhaseTaskName_ = taskName;
62     if (taskName.compare("volume") == 0) {
63         MEDIA_LOGD("0x%{public}06" PRIXPTR " task[%{public}s] start",
64             FAKE_POINTER(this), currTwoPhaseTaskName_.c_str());
65     } else {
66         MEDIA_LOGI("0x%{public}06" PRIXPTR " task[%{public}s] start",
67             FAKE_POINTER(this), currTwoPhaseTaskName_.c_str());
68     }
69 
70     return MSERR_OK;
71 }
72 
LaunchTask(const std::shared_ptr<ITaskHandler> & task,PlayerServerTaskType type,const std::string & taskName,const std::shared_ptr<ITaskHandler> & cancelTask)73 int32_t PlayerServerTaskMgr::LaunchTask(const std::shared_ptr<ITaskHandler> &task, PlayerServerTaskType type,
74     const std::string &taskName, const std::shared_ptr<ITaskHandler> &cancelTask)
75 {
76     std::unique_lock<std::mutex> lock(mutex_);
77     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
78 
79     if (taskName == "play" || taskName == "prepare") {
80         taskThread_->SetQos(QosLevel::QOS_USER_INTERACTIVE);
81     } else if (taskName == "pause") {
82         taskThread_->ResetQos();
83     }
84 
85     (void)cancelTask;
86     if (type != PlayerServerTaskType::STATE_CHANGE && type != PlayerServerTaskType::LIGHT_TASK) {
87         return MSERR_OK;
88     }
89     if (currTwoPhaseTask_ == nullptr) {
90         return EnqueueTask(task, type, taskName);
91     }
92 
93     if (taskName.compare("volume") == 0) {
94         MEDIA_LOGD("0x%{public}06" PRIXPTR " task[%{public}s] is in processing, the new task[%{public}s]",
95             FAKE_POINTER(this), currTwoPhaseTaskName_.c_str(), taskName.c_str());
96     } else {
97         MEDIA_LOGI("0x%{public}06" PRIXPTR " task[%{public}s] is in processing, the new task[%{public}s]",
98             FAKE_POINTER(this), currTwoPhaseTaskName_.c_str(), taskName.c_str());
99     }
100 
101     pendingTwoPhaseTasks_.push_back({ type, task, nullptr, taskName });
102     return MSERR_OK;
103 }
104 
SpeedTask(const std::shared_ptr<ITaskHandler> & task,const std::shared_ptr<ITaskHandler> & cancelTask,const std::string & taskName,int32_t speedMode)105 int32_t PlayerServerTaskMgr::SpeedTask(const std::shared_ptr<ITaskHandler> &task,
106     const std::shared_ptr<ITaskHandler> &cancelTask,
107     const std::string &taskName, int32_t speedMode)
108 {
109     std::unique_lock<std::mutex> lock(mutex_);
110     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
111     if (currTwoPhaseTask_ == nullptr) {
112         EnqueueTask(task, PlayerServerTaskType::RATE_CHANGE, taskName);
113         MEDIA_LOGI("speed task[%{public}s] start", currTwoPhaseTaskName_.c_str());
114         return MSERR_OK;
115     }
116     MEDIA_LOGI("current task[%{public}s] is in processing, new task[%{public}s] wait",
117         currTwoPhaseTaskName_.c_str(), taskName.c_str());
118     for (auto &item : pendingTwoPhaseTasks_) {
119         if (item.type == PlayerServerTaskType::RATE_CHANGE &&
120             item.speedMode_ != speedMode) {
121             item.type = PlayerServerTaskType::CANCEL_TASK;
122             MEDIA_LOGI("replace old speed task");
123         }
124     }
125 
126     pendingTwoPhaseTasks_.push_back({
127         PlayerServerTaskType::RATE_CHANGE, task, cancelTask, taskName, -1, -1, speedMode
128     });
129     return MSERR_OK;
130 }
131 
EnqueueSeekTask(const std::shared_ptr<ITaskHandler> & task,PlayerServerTaskType type,const std::string & taskName,int32_t seekMode,int32_t seekTime)132 int32_t PlayerServerTaskMgr::EnqueueSeekTask(const std::shared_ptr<ITaskHandler> &task,
133     PlayerServerTaskType type, const std::string &taskName, int32_t seekMode, int32_t seekTime)
134 {
135     (void)taskThread_->EnqueueTask(task);
136     currTwoPhaseTask_ = task;
137     currTwoPhaseType_ = type;
138     currTwoPhaseTaskName_ = taskName;
139     currentSeekMode_ = seekMode;
140     currentSeekTime_ = seekTime;
141     MEDIA_LOGI("0x%{public}06" PRIXPTR " seek task[%{public}s] start",
142         FAKE_POINTER(this), currTwoPhaseTaskName_.c_str());
143     return MSERR_OK;
144 }
145 
SeekTask(const std::shared_ptr<ITaskHandler> & task,const std::shared_ptr<ITaskHandler> & cancelTask,const std::string & taskName,int32_t seekMode,int32_t seekTime)146 int32_t PlayerServerTaskMgr::SeekTask(const std::shared_ptr<ITaskHandler> &task,
147     const std::shared_ptr<ITaskHandler> &cancelTask,
148     const std::string &taskName, int32_t seekMode, int32_t seekTime)
149 {
150     std::unique_lock<std::mutex> lock(mutex_);
151     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
152 
153     if (currTwoPhaseTask_ == nullptr) {
154         return EnqueueSeekTask(task, PlayerServerTaskType::SEEKING, taskName, seekMode, seekTime);
155     }
156     MEDIA_LOGI("current task[%{public}s] is in processing, new task[%{public}s] wait",
157         currTwoPhaseTaskName_.c_str(), taskName.c_str());
158     for (auto &item : pendingTwoPhaseTasks_) {
159         if (item.type == PlayerServerTaskType::SEEKING) {
160             item.type = PlayerServerTaskType::CANCEL_TASK;
161             MEDIA_LOGI("replace old seek task");
162         }
163     }
164 
165     if (currentSeekMode_ == seekMode && currentSeekTime_ == seekTime) {
166         pendingTwoPhaseTasks_.push_back({
167             PlayerServerTaskType::CANCEL_TASK, task, cancelTask, taskName, seekMode, seekTime
168         });
169         MEDIA_LOGI("abandon old seek task");
170     } else {
171         pendingTwoPhaseTasks_.push_back({
172             PlayerServerTaskType::SEEKING, task, cancelTask, taskName, seekMode, seekTime
173         });
174     }
175     return MSERR_OK;
176 }
177 
SeekContinousTask(const std::shared_ptr<ITaskHandler> & task,const std::string & taskName)178 int32_t PlayerServerTaskMgr::SeekContinousTask(const std::shared_ptr<ITaskHandler> &task, const std::string &taskName)
179 {
180     std::unique_lock<std::mutex> lock(mutex_);
181     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
182     if (currTwoPhaseTask_ == nullptr) {
183         return EnqueueTask(task, PlayerServerTaskType::SEEKING, taskName);
184     }
185     MEDIA_LOGI("0x%{public}06" PRIXPTR " task[%{public}s] is in processing, the new task[%{public}s]",
186         FAKE_POINTER(this), currTwoPhaseTaskName_.c_str(), taskName.c_str());
187     pendingTwoPhaseTasks_.push_back({ PlayerServerTaskType::SEEKING, task, nullptr, taskName });
188     return MSERR_OK;
189 }
190 
SetVideoSurfaeTask(const std::shared_ptr<ITaskHandler> & task,const std::string & taskName)191 int32_t PlayerServerTaskMgr::SetVideoSurfaeTask(const std::shared_ptr<ITaskHandler> &task, const std::string &taskName)
192 {
193     std::unique_lock<std::mutex> lock(mutex_);
194     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
195     if (currTwoPhaseTask_ == nullptr) {
196         return EnqueueTask(task, PlayerServerTaskType::SET_VIDEO_SURFACE, taskName);
197     }
198     MEDIA_LOGI("0x%{public}06" PRIXPTR " task[%{public}s] is in processing, the new task[%{public}s]",
199         FAKE_POINTER(this), currTwoPhaseTaskName_.c_str(), taskName.c_str());
200     pendingTwoPhaseTasks_.push_back({ PlayerServerTaskType::SET_VIDEO_SURFACE, task, nullptr, taskName });
201     return MSERR_OK;
202 }
203 
MarkTaskDone(const std::string & taskName)204 int32_t PlayerServerTaskMgr::MarkTaskDone(const std::string &taskName)
205 {
206     std::unique_lock<std::mutex> lock(mutex_);
207     CHECK_AND_RETURN_RET_LOG(isInited_, MSERR_INVALID_OPERATION, "not init");
208 
209     if (taskName.compare("volume done") == 0) {
210         MEDIA_LOGD("0x%{public}06" PRIXPTR " task[%{public}s] end", FAKE_POINTER(this), taskName.c_str());
211     } else {
212         MEDIA_LOGI("0x%{public}06" PRIXPTR " task[%{public}s] end", FAKE_POINTER(this), taskName.c_str());
213     }
214     currTwoPhaseTask_ = nullptr;
215     currTwoPhaseType_ = PlayerServerTaskType::BUTT;
216     currTwoPhaseTaskName_ = "None";
217     currentSeekMode_ = -1;
218     currentSeekTime_ = -1;
219 
220     if (!pendingTwoPhaseTasks_.empty()) {
221         auto item = pendingTwoPhaseTasks_.front();
222         pendingTwoPhaseTasks_.pop_front();
223         currTwoPhaseType_ = item.type;
224         if (item.type == PlayerServerTaskType::CANCEL_TASK) {
225             currTwoPhaseTask_ = item.cancelTask;
226         } else {
227             currTwoPhaseTask_ = item.task;
228         }
229         currTwoPhaseTaskName_ = item.taskName;
230         if (item.type == PlayerServerTaskType::SEEKING) {
231             currentSeekMode_ = item.seekMode_;
232             currentSeekTime_ = item.seekTime_;
233         }
234 
235         CHECK_AND_RETURN_RET_LOG(currTwoPhaseTask_ != nullptr, MSERR_OK, "task is nullptr");
236         int32_t ret = taskThread_->EnqueueTask(currTwoPhaseTask_);
237         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret,
238             "execute the stack top task failed, type: %{public}hhu", item.type);
239 
240         MEDIA_LOGD("0x%{public}06" PRIXPTR " task[%{public}s] start",
241             FAKE_POINTER(this), currTwoPhaseTaskName_.c_str());
242     }
243     return MSERR_OK;
244 }
245 
ClearAllTask()246 void PlayerServerTaskMgr::ClearAllTask()
247 {
248     MEDIA_LOGD("enter");
249     std::unique_lock<std::mutex> lock(mutex_);
250     CHECK_AND_RETURN_LOG(isInited_, "not init");
251 
252     currTwoPhaseTask_ = nullptr;
253     currTwoPhaseType_ = PlayerServerTaskType::BUTT;
254     pendingTwoPhaseTasks_.clear();
255 
256     auto dummyTask = std::make_shared<TaskHandler<void>>([this]() {
257         MEDIA_LOGD("0x%{public}06" PRIXPTR " execute dummy task...", FAKE_POINTER(this));
258     });
259     (void)taskThread_->EnqueueTask(dummyTask, true, 0);
260     MEDIA_LOGD("exit");
261 }
262 
Reset()263 int32_t PlayerServerTaskMgr::Reset()
264 {
265     MEDIA_LOGD("enter");
266     std::unique_lock<std::mutex> lock(mutex_);
267 
268     currTwoPhaseTask_ = nullptr;
269     currTwoPhaseType_ = PlayerServerTaskType::BUTT;
270     pendingTwoPhaseTasks_.clear();
271     isInited_ = false;
272 
273     if (taskThread_ != nullptr) {
274         std::unique_ptr<TaskQueue> tmp;
275         std::swap(tmp, taskThread_);
276 
277         lock.unlock();
278         int32_t ret = tmp->Stop();
279         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "stop task thread failed");
280         lock.lock();
281     }
282 
283     MEDIA_LOGD("exit");
284     return MSERR_OK;
285 }
286 }
287 }
288