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