• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2022 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 #define HST_LOG_TAG "CallbackLooper"
17 
18 #include "hiplayer_callback_looper.h"
19 #include <utility>
20 #include "common/log.h"
21 #include "osal/task/autolock.h"
22 #include "osal/utils/steady_clock.h"
23 
24 namespace OHOS {
25 namespace Media {
26 namespace {
27 constexpr int32_t WHAT_NONE = 0;
28 constexpr int32_t WHAT_MEDIA_PROGRESS = 1;
29 constexpr int32_t WHAT_INFO = 2;
30 constexpr int32_t WHAT_ERROR = 3;
31 
32 constexpr int32_t TUPLE_POS_0 = 0;
33 constexpr int32_t TUPLE_POS_1 = 1;
34 constexpr int32_t TUPLE_POS_2 = 2;
35 }
HiPlayerCallbackLooper()36 HiPlayerCallbackLooper::HiPlayerCallbackLooper() : task_("callbackThread", OHOS::Media::TaskPriority::NORMAL)
37 {
38     task_.RegisterJob([this] {LoopOnce();});
39 }
40 
~HiPlayerCallbackLooper()41 HiPlayerCallbackLooper::~HiPlayerCallbackLooper()
42 {
43     Stop();
44 }
45 
IsStarted()46 bool HiPlayerCallbackLooper::IsStarted()
47 {
48     return taskStarted_;
49 }
50 
Stop()51 void HiPlayerCallbackLooper::Stop()
52 {
53     if (taskStarted_) {
54         eventQueue_.Quit();
55         task_.Stop();
56         taskStarted_ = false;
57     }
58 }
59 
StartWithPlayerEngineObs(const std::weak_ptr<IPlayerEngineObs> & obs)60 void HiPlayerCallbackLooper::StartWithPlayerEngineObs(const std::weak_ptr<IPlayerEngineObs>& obs)
61 {
62     OHOS::Media::AutoLock lock(loopMutex_);
63     obs_ = obs;
64     if (!taskStarted_) {
65         task_.Start();
66         taskStarted_ = true;
67         MEDIA_LOG_I("start callback looper");
68     }
69 }
SetPlayEngine(IPlayerEngine * engine)70 void HiPlayerCallbackLooper::SetPlayEngine(IPlayerEngine* engine)
71 {
72     OHOS::Media::AutoLock lock(loopMutex_);
73     playerEngine_ = engine;
74 }
75 
StartReportMediaProgress(int64_t updateIntervalMs)76 void HiPlayerCallbackLooper::StartReportMediaProgress(int64_t updateIntervalMs)
77 {
78     reportProgressIntervalMs_ = updateIntervalMs;
79     if (reportMediaProgress_) { // already set
80         return;
81     }
82     reportMediaProgress_ = true;
83     eventQueue_.Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS, SteadyClock::GetCurrentTimeMs(), Any()));
84 }
85 
ManualReportMediaProgressOnce()86 void HiPlayerCallbackLooper::ManualReportMediaProgressOnce()
87 {
88     eventQueue_.Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS, SteadyClock::GetCurrentTimeMs(), Any()));
89 }
90 
StopReportMediaProgress()91 void HiPlayerCallbackLooper::StopReportMediaProgress()
92 {
93     reportMediaProgress_ = false;
94 }
95 
DropMediaProgress()96 void HiPlayerCallbackLooper::DropMediaProgress()
97 {
98     isDropMediaProgress_ = true;
99     eventQueue_.RemoveMediaProgressEvent();
100 }
101 
DoReportCompletedTime()102 void HiPlayerCallbackLooper::DoReportCompletedTime()
103 {
104     OHOS::Media::AutoLock lock(loopMutex_);
105     auto obs = obs_.lock();
106     if (obs) {
107         Format format;
108         int32_t currentPositionMs;
109         if (playerEngine_->GetDuration(currentPositionMs) == 0) {
110             MEDIA_LOG_DD("EVENT_AUDIO_PROGRESS completed position updated: " PUBLIC_LOG_D32, currentPositionMs);
111             obs->OnInfo(INFO_TYPE_POSITION_UPDATE, currentPositionMs, format);
112         } else {
113             MEDIA_LOG_W("get player engine current time error");
114         }
115     }
116 }
117 
DoReportMediaProgress()118 void HiPlayerCallbackLooper::DoReportMediaProgress()
119 {
120     OHOS::Media::AutoLock lock(loopMutex_);
121     auto obs = obs_.lock();
122     if (obs && !isDropMediaProgress_) {
123         Format format;
124         int32_t currentPositionMs;
125         if (playerEngine_->GetCurrentTime(currentPositionMs) == 0) {
126             MEDIA_LOG_DD("EVENT_AUDIO_PROGRESS position updated: " PUBLIC_LOG_D32, currentPositionMs);
127             obs->OnInfo(INFO_TYPE_POSITION_UPDATE, currentPositionMs, format);
128         } else {
129             MEDIA_LOG_W("get player engine current time error");
130         }
131     }
132     isDropMediaProgress_ = false;
133     if (reportMediaProgress_) {
134         eventQueue_.Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS,
135             SteadyClock::GetCurrentTimeMs() + reportProgressIntervalMs_, Any()));
136     }
137 }
138 
OnError(PlayerErrorType errorType,int32_t errorCode)139 void HiPlayerCallbackLooper::OnError(PlayerErrorType errorType, int32_t errorCode)
140 {
141     eventQueue_.Enqueue(std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_ERROR, SteadyClock::GetCurrentTimeMs(),
142     std::make_pair(errorType, errorCode)));
143 }
144 
DoReportError(const Any & error)145 void HiPlayerCallbackLooper::DoReportError(const Any &error)
146 {
147     OHOS::Media::AutoLock lock(loopMutex_);
148     auto obs = obs_.lock();
149     if (obs != nullptr) {
150         auto ptr = AnyCast<std::pair<PlayerErrorType, int32_t>>(&error);
151         MEDIA_LOG_E("Report error, error type: " PUBLIC_LOG_D32 " error value: " PUBLIC_LOG_D32,
152             static_cast<int32_t>(ptr->first), static_cast<int32_t>(ptr->second));
153         obs->OnError(ptr->first, ptr->second);
154     }
155 }
156 
OnInfo(PlayerOnInfoType type,int32_t extra,const Format & infoBody)157 void HiPlayerCallbackLooper::OnInfo(PlayerOnInfoType type, int32_t extra, const Format &infoBody)
158 {
159     eventQueue_.Enqueue(std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_INFO, SteadyClock::GetCurrentTimeMs(),
160         std::make_tuple(type, extra, infoBody)));
161 }
162 
DoReportInfo(const Any & info)163 void HiPlayerCallbackLooper::DoReportInfo(const Any& info)
164 {
165     auto obs = obs_.lock();
166     if (obs != nullptr) {
167         auto ptr = AnyCast<std::tuple<PlayerOnInfoType, int32_t, Format>>(&info);
168         MEDIA_LOG_I("Report info, info type: " PUBLIC_LOG_D32 " info value: " PUBLIC_LOG_D32,
169             static_cast<int32_t>(std::get<TUPLE_POS_0>(*ptr)), static_cast<int32_t>(std::get<TUPLE_POS_1>(*ptr)));
170         obs->OnInfo(std::get<TUPLE_POS_0>(*ptr), std::get<TUPLE_POS_1>(*ptr), std::get<TUPLE_POS_2>(*ptr));
171     }
172 }
173 
LoopOnce()174 void HiPlayerCallbackLooper::LoopOnce()
175 {
176     auto item = eventQueue_.Next();
177     switch (item->what) {
178         case WHAT_MEDIA_PROGRESS:
179             DoReportMediaProgress();
180             break;
181         case WHAT_INFO:
182             DoReportInfo(item->detail);
183             break;
184         case WHAT_ERROR:
185             DoReportError(item->detail);
186             break;
187         default:
188             break;
189     }
190 }
191 
Enqueue(const std::shared_ptr<HiPlayerCallbackLooper::Event> & event)192 void HiPlayerCallbackLooper::EventQueue::Enqueue(const std::shared_ptr<HiPlayerCallbackLooper::Event>& event)
193 {
194     if (event->what == WHAT_NONE) {
195         MEDIA_LOG_I("invalid event");
196     }
197     OHOS::Media::AutoLock lock(queueMutex_);
198     if (quit_) {
199         MEDIA_LOG_W("event already quit");
200         return;
201     }
202     auto ite = queue_.begin();
203     for (; ite != queue_.end(); ite++) {
204         if ((*ite)->whenMs > event->whenMs) {
205             break;
206         }
207     }
208     auto pos = queue_.insert(ite, event);
209     if (pos == queue_.begin()) {
210         queueHeadUpdatedCond_.NotifyOne();
211     }
212 }
213 
Next()214 std::shared_ptr<HiPlayerCallbackLooper::Event> HiPlayerCallbackLooper::EventQueue::Next()
215 {
216     OHOS::Media::AutoLock lock(queueMutex_);
217     // not empty
218     while (queue_.empty() && !quit_) {
219         queueHeadUpdatedCond_.Wait(lock);
220     }
221 
222     do {
223         if (quit_) {
224             return std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_NONE, 0, Any());
225         }
226         auto wakenAtTime = (*queue_.begin())->whenMs;
227         auto leftTime = wakenAtTime - SteadyClock::GetCurrentTimeMs();
228         if (leftTime <= 0) {
229             auto first = *queue_.begin();
230             queue_.erase(queue_.begin());
231             return first;
232         }
233         queueHeadUpdatedCond_.WaitFor(lock, leftTime);
234     } while (1);
235 }
236 
Quit()237 void HiPlayerCallbackLooper::EventQueue::Quit()
238 {
239     OHOS::Media::AutoLock lock(queueMutex_);
240     quit_ = true;
241     queueHeadUpdatedCond_.NotifyOne();
242 }
243 
RemoveMediaProgressEvent()244 void HiPlayerCallbackLooper::EventQueue::RemoveMediaProgressEvent()
245 {
246     OHOS::Media::AutoLock lock(queueMutex_);
247     for (auto iter = queue_.begin(); iter != queue_.end(); iter++) {
248         if ((*iter)->what == WHAT_MEDIA_PROGRESS) {
249             (*iter)->what = WHAT_NONE;
250         }
251     }
252 }
253 }  // namespace Media
254 }  // namespace OHOS