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 {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "HiPlayerCallbackLooper" };
26 }
27 
28 namespace OHOS {
29 namespace Media {
30 namespace {
31 constexpr int32_t WHAT_NONE = 0;
32 constexpr int32_t WHAT_MEDIA_PROGRESS = 1;
33 constexpr int32_t WHAT_INFO = 2;
34 constexpr int32_t WHAT_ERROR = 3;
35 constexpr int32_t WHAT_COLLECT_AMPLITUDE = 4;
36 constexpr int32_t WHAT_SYSTEM_OPERATION = 5;
37 
38 constexpr int32_t TUPLE_POS_0 = 0;
39 constexpr int32_t TUPLE_POS_1 = 1;
40 constexpr int32_t TUPLE_POS_2 = 2;
41 constexpr int32_t MAX_AMPLITUDE_SIZE = 5;
42 }
HiPlayerCallbackLooper()43 HiPlayerCallbackLooper::HiPlayerCallbackLooper()
44 {
45 }
46 
~HiPlayerCallbackLooper()47 HiPlayerCallbackLooper::~HiPlayerCallbackLooper()
48 {
49     Stop();
50 }
51 
IsStarted()52 bool HiPlayerCallbackLooper::IsStarted()
53 {
54     return taskStarted_;
55 }
56 
Stop()57 void HiPlayerCallbackLooper::Stop()
58 {
59     if (taskStarted_) {
60         task_->Stop();
61         taskStarted_ = false;
62     }
63 }
64 
StartWithPlayerEngineObs(const std::weak_ptr<IPlayerEngineObs> & obs)65 void HiPlayerCallbackLooper::StartWithPlayerEngineObs(const std::weak_ptr<IPlayerEngineObs>& obs)
66 {
67     OHOS::Media::AutoLock lock(loopMutex_);
68     obs_ = obs;
69     if (!taskStarted_) {
70         task_->Start();
71         taskStarted_ = true;
72         MEDIA_LOG_I("start callback looper");
73     }
74 }
SetPlayEngine(IPlayerEngine * engine,std::string playerId)75 void HiPlayerCallbackLooper::SetPlayEngine(IPlayerEngine* engine, std::string playerId)
76 {
77     OHOS::Media::AutoLock lock(loopMutex_);
78     playerEngine_ = engine;
79     task_ = std::make_unique<Task>("callbackThread", playerId, TaskType::GLOBAL, TaskPriority::NORMAL, false);
80 }
81 
StartReportMediaProgress(int64_t updateIntervalMs)82 void HiPlayerCallbackLooper::StartReportMediaProgress(int64_t updateIntervalMs)
83 {
84     MEDIA_LOG_I("HiPlayerCallbackLooper StartReportMediaProgress");
85     reportProgressIntervalMs_ = updateIntervalMs;
86     if (reportMediaProgress_) { // already set
87         return;
88     }
89     reportMediaProgress_ = true;
90     Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS,
91             SteadyClock::GetCurrentTimeMs() + reportProgressIntervalMs_, Any()));
92 }
93 
StartCollectMaxAmplitude(int64_t updateIntervalMs)94 void HiPlayerCallbackLooper::StartCollectMaxAmplitude(int64_t updateIntervalMs)
95 {
96     MEDIA_LOG_I("HiPlayerCallbackLooper StartCollectMaxAmplitude");
97     collectMaxAmplitudeIntervalMs_ = updateIntervalMs;
98     if (collectMaxAmplitude_) { // already set
99         return;
100     }
101     collectMaxAmplitude_ = true;
102     Enqueue(std::make_shared<Event>(WHAT_COLLECT_AMPLITUDE,
103             SteadyClock::GetCurrentTimeMs() + collectMaxAmplitudeIntervalMs_, Any()));
104 }
105 
ManualReportMediaProgressOnce()106 void HiPlayerCallbackLooper::ManualReportMediaProgressOnce()
107 {
108     Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS, SteadyClock::GetCurrentTimeMs(), Any()));
109 }
110 
StopReportMediaProgress()111 void HiPlayerCallbackLooper::StopReportMediaProgress()
112 {
113     MEDIA_LOG_I("HiPlayerCallbackLooper StopReportMediaProgress");
114     OHOS::Media::AutoLock lock(loopMutex_);
115     reportMediaProgress_ = false;
116 }
117 
StopCollectMaxAmplitude()118 void HiPlayerCallbackLooper::StopCollectMaxAmplitude()
119 {
120     MEDIA_LOG_I("HiPlayerCallbackLooper StopCollectMaxAmplitude");
121     OHOS::Media::AutoLock lock(loopMutex_);
122     collectMaxAmplitude_ = false;
123 }
124 
DoReportCompletedTime()125 void HiPlayerCallbackLooper::DoReportCompletedTime()
126 {
127     OHOS::Media::AutoLock lock(loopMutex_);
128     auto obs = obs_.lock();
129     if (obs) {
130         Format format;
131         int32_t playRangeEndTime = static_cast<int32_t>(playerEngine_->GetPlayRangeEndTime());
132         if (playRangeEndTime != -1) {
133             MEDIA_LOG_D("EVENT_AUDIO_PROGRESS endTime position updated: " PUBLIC_LOG_D32, playRangeEndTime);
134             obs->OnInfo(INFO_TYPE_POSITION_UPDATE, playRangeEndTime, format);
135         } else {
136             int32_t currentPositionMs;
137             if (playerEngine_->GetDuration(currentPositionMs) == 0) {
138                 MEDIA_LOG_D("EVENT_AUDIO_PROGRESS completed position updated: " PUBLIC_LOG_D32, currentPositionMs);
139                 obs->OnInfo(INFO_TYPE_POSITION_UPDATE, currentPositionMs, format);
140             } else {
141                 MEDIA_LOG_W("get player engine current time error");
142             }
143         }
144     }
145 }
146 
DoReportMediaProgress()147 void HiPlayerCallbackLooper::DoReportMediaProgress()
148 {
149     OHOS::Media::AutoLock lock(loopMutex_);
150     if (!reportMediaProgress_) {
151         return;
152     }
153     auto obs = obs_.lock();
154     if (obs && !isDropMediaProgress_) {
155         Format format;
156         int32_t currentPositionMs;
157         if (playerEngine_->GetCurrentTime(currentPositionMs) == 0) {
158             MEDIA_LOG_D("EVENT_AUDIO_PROGRESS position updated: " PUBLIC_LOG_D32, currentPositionMs);
159             obs->OnInfo(INFO_TYPE_POSITION_UPDATE, currentPositionMs, format);
160         } else {
161             MEDIA_LOG_W("get player engine current time error");
162         }
163     }
164     isDropMediaProgress_ = false;
165     if (reportMediaProgress_) {
166         Enqueue(std::make_shared<Event>(WHAT_MEDIA_PROGRESS,
167             SteadyClock::GetCurrentTimeMs() + reportProgressIntervalMs_, Any()));
168     }
169 }
170 
DoCollectAmplitude()171 void HiPlayerCallbackLooper::DoCollectAmplitude()
172 {
173     OHOS::Media::AutoLock lock(loopMutex_);
174     if (!collectMaxAmplitude_) {
175         return;
176     }
177     auto obs = obs_.lock();
178     if (obs) {
179         float maxAmplitude = 0.0f;
180         maxAmplitude = playerEngine_->GetMaxAmplitude();
181         vMaxAmplitudeArray_.push_back(maxAmplitude);
182         if (vMaxAmplitudeArray_.size() == MAX_AMPLITUDE_SIZE) {
183             int mSize = static_cast<int>(vMaxAmplitudeArray_.size());
184             const int size = mSize;
185             float* maxAmplitudeArray = vMaxAmplitudeArray_.data();
186             Format amplitudeFormat;
187             (void)amplitudeFormat.PutBuffer(std::string(PlayerKeys::AUDIO_MAX_AMPLITUDE),
188                 static_cast<uint8_t *>(static_cast<void *>(maxAmplitudeArray)), size * sizeof(float));
189             obs->OnInfo(INFO_TYPE_MAX_AMPLITUDE_COLLECT, 0, amplitudeFormat);
190             vMaxAmplitudeArray_.clear();
191         }
192     }
193     if (collectMaxAmplitude_) {
194         Enqueue(std::make_shared<Event>(WHAT_COLLECT_AMPLITUDE,
195             SteadyClock::GetCurrentTimeMs() + collectMaxAmplitudeIntervalMs_, Any()));
196     }
197 }
198 
ReportRemainedMaxAmplitude()199 void HiPlayerCallbackLooper::ReportRemainedMaxAmplitude()
200 {
201     OHOS::Media::AutoLock lock(loopMutex_);
202     auto obs = obs_.lock();
203     if (obs != nullptr) {
204         if (vMaxAmplitudeArray_.size() != 0) {
205             const int size = static_cast<int>(vMaxAmplitudeArray_.size());
206             float* maxAmplitudeArray = vMaxAmplitudeArray_.data();
207             Format amplitudeFormat;
208             (void)amplitudeFormat.PutBuffer(std::string(PlayerKeys::AUDIO_MAX_AMPLITUDE),
209                 static_cast<uint8_t *>(static_cast<void *>(maxAmplitudeArray)), size * sizeof(float));
210             obs->OnInfo(INFO_TYPE_MAX_AMPLITUDE_COLLECT, 0, amplitudeFormat);
211             vMaxAmplitudeArray_.clear();
212         }
213     }
214 }
215 
DoReportSystemOperation(const Any & info)216 void HiPlayerCallbackLooper::DoReportSystemOperation(const Any& info)
217 {
218     std::shared_ptr<IPlayerEngineObs> obs;
219     {
220         OHOS::Media::AutoLock lock(loopMutex_);
221         obs = obs_.lock();
222     }
223     if (obs) {
224         auto ptr = AnyCast<std::pair<PlayerOnSystemOperationType, PlayerOperationReason>>(&info);
225         if (ptr == nullptr) {
226             MEDIA_LOG_E_SHORT("DoReportSystemOperation, ptr is nullptr");
227             return;
228         }
229         MEDIA_LOG_I("Do Report SystemOperation, type: " PUBLIC_LOG_D32 " resaon: " PUBLIC_LOG_D32,
230             static_cast<int32_t>(ptr->first), static_cast<int32_t>(ptr->second));
231         obs->OnSystemOperation(ptr->first, ptr->second);
232     }
233 }
234 
OnError(PlayerErrorType errorType,int32_t errorCode)235 void HiPlayerCallbackLooper::OnError(PlayerErrorType errorType, int32_t errorCode)
236 {
237     Enqueue(std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_ERROR, SteadyClock::GetCurrentTimeMs(),
238     std::make_pair(errorType, errorCode)));
239 }
240 
DoReportError(const Any & error)241 void HiPlayerCallbackLooper::DoReportError(const Any &error)
242 {
243     OHOS::Media::AutoLock lock(loopMutex_);
244     auto obs = obs_.lock();
245     if (obs != nullptr) {
246         auto ptr = AnyCast<std::pair<PlayerErrorType, int32_t>>(&error);
247         if (ptr == nullptr) {
248             MEDIA_LOG_E_SHORT("DoReportError error, ptr is nullptr");
249             return;
250         }
251         MEDIA_LOG_E("Report error, error type: " PUBLIC_LOG_D32 " error value: " PUBLIC_LOG_D32,
252             static_cast<int32_t>(ptr->first), static_cast<int32_t>(ptr->second));
253         obs->OnError(ptr->first, ptr->second);
254     }
255 }
256 
OnSystemOperation(PlayerOnSystemOperationType type,PlayerOperationReason reason)257 void HiPlayerCallbackLooper::OnSystemOperation(PlayerOnSystemOperationType type, PlayerOperationReason reason)
258 {
259     Enqueue(std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_SYSTEM_OPERATION, SteadyClock::GetCurrentTimeMs(),
260         std::make_pair(type, reason)));
261 }
262 
OnInfo(PlayerOnInfoType type,int32_t extra,const Format & infoBody)263 void HiPlayerCallbackLooper::OnInfo(PlayerOnInfoType type, int32_t extra, const Format &infoBody)
264 {
265     Enqueue(std::make_shared<HiPlayerCallbackLooper::Event>(WHAT_INFO, SteadyClock::GetCurrentTimeMs(),
266         std::make_tuple(type, extra, infoBody)));
267 }
268 
DoReportInfo(const Any & info)269 void HiPlayerCallbackLooper::DoReportInfo(const Any& info)
270 {
271     auto obs = obs_.lock();
272     if (obs != nullptr) {
273         auto ptr = AnyCast<std::tuple<PlayerOnInfoType, int32_t, Format>>(&info);
274         if (ptr == nullptr) {
275             MEDIA_LOG_E_SHORT("DoReportInfo error, ptr is nullptr");
276             return;
277         }
278         MEDIA_LOG_I("Report info, info type: " PUBLIC_LOG_D32 " info value: " PUBLIC_LOG_D32,
279             static_cast<int32_t>(std::get<TUPLE_POS_0>(*ptr)), static_cast<int32_t>(std::get<TUPLE_POS_1>(*ptr)));
280         obs->OnInfo(std::get<TUPLE_POS_0>(*ptr), std::get<TUPLE_POS_1>(*ptr), std::get<TUPLE_POS_2>(*ptr));
281     }
282 }
283 
LoopOnce(const std::shared_ptr<HiPlayerCallbackLooper::Event> & item)284 void HiPlayerCallbackLooper::LoopOnce(const std::shared_ptr<HiPlayerCallbackLooper::Event>& item)
285 {
286     switch (item->what) {
287         case WHAT_MEDIA_PROGRESS:
288             DoReportMediaProgress();
289             break;
290         case WHAT_INFO:
291             DoReportInfo(item->detail);
292             break;
293         case WHAT_ERROR:
294             DoReportError(item->detail);
295             break;
296         case WHAT_COLLECT_AMPLITUDE:
297             DoCollectAmplitude();
298             break;
299         case WHAT_SYSTEM_OPERATION:
300             DoReportSystemOperation(item->detail);
301             break;
302         default:
303             break;
304     }
305 }
306 
Enqueue(const std::shared_ptr<HiPlayerCallbackLooper::Event> & event)307 void HiPlayerCallbackLooper::Enqueue(const std::shared_ptr<HiPlayerCallbackLooper::Event>& event)
308 {
309     if (event->what == WHAT_NONE) {
310         MEDIA_LOG_I("invalid event");
311     }
312     int64_t delayUs = (event->whenMs - SteadyClock::GetCurrentTimeMs()) * 1000;
313     task_->SubmitJob([this, event]() {
314         LoopOnce(event);
315     }, delayUs);
316 }
317 }  // namespace Media
318 }  // namespace OHOS