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 #include "acelite_config.h"
16 #if (FEATURE_COMPONENT_VIDEO == 1)
17 #include "video_component.h"
18 #include "ace_log.h"
19 #include "key_parser.h"
20 #include "keys.h"
21 
22 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1)
23 #include <sys/prctl.h>
24 #include "ace_ability.h"
25 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC
26 
27 namespace OHOS {
28 namespace ACELite {
29 const char * const VideoComponent::FUNC_START = "start";
30 const char * const VideoComponent::FUNC_PAUSE = "pause";
31 const char * const VideoComponent::FUNC_SET_CURRENT_TIME = "setCurrentTime";
32 const char * const VideoComponent::FUNC_SET_Volume = "setVolume";
33 List<Component *> VideoComponent::componentNodes_;
34 
35 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1)
36 pthread_mutex_t VideoComponent::updateLock_ = PTHREAD_MUTEX_INITIALIZER;
37 pthread_cond_t VideoComponent::updateCondition_ = PTHREAD_COND_INITIALIZER;
38 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYN
39 
VideoComponent(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)40 VideoComponent::VideoComponent(jerry_value_t options, jerry_value_t children, AppStyleManager *styleManager)
41     : Component(options, children, styleManager),
42       videoSourceUrl_(nullptr),
43       videoView_(nullptr),
44       videoEventListener_(nullptr),
45       videoSliderListener_(nullptr),
46       videoPlayImageClickListener_(nullptr),
47       autoPlay_(false),
48       videoMuted_(false),
49       isPlaying_(false),
50       isReleasing_(false),
51       isUpdatingHandlerQuited_(false)
52 {
53     SetComponentName(K_VIDEO);
54     RegisterNativeFunctions();
55 }
56 
RegisterNativeFunctions()57 void VideoComponent::RegisterNativeFunctions()
58 {
59     RegisterNamedFunction(FUNC_START, Start);
60     RegisterNamedFunction(FUNC_PAUSE, Pause);
61     RegisterNamedFunction(FUNC_SET_CURRENT_TIME, SetCurrentTime);
62     RegisterNamedFunction(FUNC_SET_Volume, SetVolume);
63 }
64 
UpdatePlayImageInfo(bool playFlag)65 void VideoComponent::UpdatePlayImageInfo(bool playFlag)
66 {
67     PanelView* panelView = const_cast<PanelView *>(videoView_->GetPanelView());
68     if (panelView == nullptr) {
69         HILOG_ERROR(HILOG_MODULE_ACE, "video panel get panelview is nullptr");
70         return;
71     }
72     UIImageView *playImageView = const_cast<UIImageView *>(panelView->GetVideoPlayImage());
73     if (playImageView == nullptr) {
74         HILOG_ERROR(HILOG_MODULE_ACE, "video panel get play image view is nullptr");
75         return;
76     }
77     const ImageInfo* imageSrc = playFlag ? GetVideoPlayImageOffInfo() : GetVideoPlayImageOnInfo();
78     playImageView->SetSrc(imageSrc);
79     if (videoPlayImageClickListener_ == nullptr) {
80         HILOG_ERROR(HILOG_MODULE_ACE, "video panel get image click listener is nullptr");
81         return;
82     }
83     videoPlayImageClickListener_->setVideoPlayImageClickStatus(playFlag);
84 }
85 
Start(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)86 JSValue VideoComponent::Start(const jerry_value_t func,
87                               const jerry_value_t context,
88                               const jerry_value_t args[],
89                               const jerry_length_t argsNum)
90 {
91     VideoView *nativeVideo = reinterpret_cast<VideoView *>(ComponentUtils::GetViewFromBindingObject(context));
92     if (nativeVideo == nullptr) {
93         return UNDEFINED;
94     }
95     VideoComponent *videoComponent
96         = reinterpret_cast<VideoComponent *>(ComponentUtils::GetComponentFromBindingObject(context));
97     if (videoComponent == nullptr) {
98         return UNDEFINED;
99     }
100     if ((nativeVideo->Play()) != 0) {
101         HILOG_ERROR(HILOG_MODULE_ACE, "call VideoComponent::Start failed");
102         return UNDEFINED;
103     }
104     videoComponent->UpdatePlayImageInfo(true);
105     HILOG_DEBUG(HILOG_MODULE_ACE, "nativeVideo Start");
106     return UNDEFINED;
107 }
108 
Pause(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)109 JSValue VideoComponent::Pause(const jerry_value_t func,
110                               const jerry_value_t context,
111                               const jerry_value_t args[],
112                               const jerry_length_t argsNum)
113 {
114     VideoView *nativeVideo = reinterpret_cast<VideoView *>(ComponentUtils::GetViewFromBindingObject(context));
115     if (nativeVideo == nullptr) {
116         return UNDEFINED;
117     }
118     VideoComponent *videoComponent =
119         reinterpret_cast<VideoComponent *>(ComponentUtils::GetComponentFromBindingObject(context));
120     if (videoComponent == nullptr) {
121         return UNDEFINED;
122     }
123     if ((nativeVideo->Pause()) != 0) {
124         HILOG_ERROR(HILOG_MODULE_ACE, "call VideoComponent::Pause failed");
125         return UNDEFINED;
126     }
127     // update panel info
128     videoComponent->UpdatePlayImageInfo(false);
129     return UNDEFINED;
130 }
131 
SetCurrentTime(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)132 JSValue VideoComponent::SetCurrentTime(const jerry_value_t func,
133                                        const jerry_value_t context,
134                                        const jerry_value_t args[],
135                                        const jerry_length_t argsNum)
136 {
137     VideoView *nativeVideo = reinterpret_cast<VideoView *>(ComponentUtils::GetViewFromBindingObject(context));
138     if (nativeVideo == nullptr || argsNum != 1) {
139         return UNDEFINED;
140     }
141     int16_t currentTime = IntegerOf(args[0]);
142     if (nativeVideo->SeekTo(currentTime * PanelView::MILLIONS_PER_SECOND) != 0) {
143         HILOG_ERROR(HILOG_MODULE_ACE, "call VideoComponent::SetCurrentTime failed");
144         return UNDEFINED;
145     }
146     // update panel view slider info
147     nativeVideo->UpdatePanelTimeText(true);
148     return UNDEFINED;
149 }
150 
SetVolume(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)151 JSValue VideoComponent::SetVolume(const jerry_value_t func,
152                                   const jerry_value_t context,
153                                   const jerry_value_t args[],
154                                   const jerry_length_t argsNum)
155 {
156     VideoView *nativeVideo = reinterpret_cast<VideoView *>(ComponentUtils::GetViewFromBindingObject(context));
157     if (nativeVideo != nullptr && argsNum == 1) {
158         int16_t volumeValue = IntegerOf(args[0]);
159         if ((nativeVideo->SetVolume(volumeValue)) != 0) {
160             HILOG_ERROR(HILOG_MODULE_ACE, "call VideoComponent::SetVolume failed");
161             return UNDEFINED;
162         }
163     }
164     return UNDEFINED;
165 }
166 
CreateNativeViews()167 bool VideoComponent::CreateNativeViews()
168 {
169     videoView_ = new VideoView();
170     if (videoView_ == nullptr) {
171         HILOG_ERROR(HILOG_MODULE_ACE, "VideoComponent: create VideoView object failed!");
172         return false;
173     }
174     videoView_->SetPlayStateCallback(this);
175     if (!videoView_->CreateVideoView()) {
176         return false;
177     }
178     videoSliderListener_ = new VideoSliderEventListener(videoView_);
179     if (videoSliderListener_ == nullptr) {
180         HILOG_ERROR(HILOG_MODULE_ACE, "create videoSliderListener_ event failed");
181         return false;
182     }
183     videoPlayImageClickListener_ = new VideoPlayImageOnClickListener(videoView_);
184     if (videoPlayImageClickListener_ == nullptr) {
185         HILOG_ERROR(HILOG_MODULE_ACE, "create video slider listener failed");
186         return false;
187     }
188     videoEventListener_ = std::make_shared<VideoEventListener>(videoView_, videoPlayImageClickListener_);
189     if (videoEventListener_ == nullptr) {
190         HILOG_ERROR(HILOG_MODULE_ACE, "VideoComponent: create videoEventListener_ failed!");
191         return false;
192     }
193     if (!RegisterVideoEventListener()) {
194         return false;
195     }
196     AddComponentNode(this);
197     return PrepareProgressUpdatingThread();
198 }
199 
ReleaseNativeViews()200 void VideoComponent::ReleaseNativeViews()
201 {
202     RemoveComponentNode(this);
203     SetComponentReleasingFlag(true);
204     // wait until the updating thread destroyed
205     pthread_cond_signal(&updateCondition_);
206     const uint16_t waitThreadDestroyTime = 20000;
207     while (!isUpdatingHandlerQuited_) {
208         usleep(waitThreadDestroyTime);
209     }
210     ACE_DELETE(videoView_);
211     ACE_DELETE(videoSliderListener_);
212     ACE_DELETE(videoPlayImageClickListener_);
213     ACE_FREE(videoSourceUrl_);
214     SetComponentReleasingFlag(false);
215 }
216 
GetComponentRootView() const217 UIView *VideoComponent::GetComponentRootView() const
218 {
219     return videoView_;
220 }
221 
RegisterVideoEventListener()222 bool VideoComponent::RegisterVideoEventListener()
223 {
224     PanelView* videoPanelView = const_cast<PanelView *>(videoView_->GetPanelView());
225     if (videoPanelView == nullptr) {
226         return false;
227     }
228 
229     UISlider *videoSlider = const_cast<UISlider *>(videoPanelView->GetVideoSlider());
230     if (videoSlider == nullptr) {
231         HILOG_ERROR(HILOG_MODULE_ACE, "create get video slider failed");
232         return false;
233     }
234     videoSlider->SetSliderEventListener(videoSliderListener_);
235     videoSlider->SetOnClickListener(videoSliderListener_);
236     videoSlider->SetTouchable(true);
237     videoSlider->SetDraggable(true);
238 
239     UIImageView *videoPlayImage = const_cast<UIImageView *>(videoPanelView->GetVideoPlayImage());
240     if (videoPlayImage == nullptr) {
241         HILOG_ERROR(HILOG_MODULE_ACE, "create get video play image failed");
242         return false;
243     }
244     videoPlayImage->SetOnClickListener(videoPlayImageClickListener_);
245     videoPlayImage->SetTouchable(true);
246 
247     UIImageView *videoMutedImage = const_cast<UIImageView *>(videoPanelView->GetVideoMutedImage());
248     if (videoMutedImage == nullptr) {
249         HILOG_ERROR(HILOG_MODULE_ACE, "create get video muted image failed");
250         return false;
251     }
252     videoMutedImage->SetOnClickListener(videoPlayImageClickListener_);
253     videoMutedImage->SetTouchable(true);
254 
255     Media::Player *videoPlayer = const_cast<Media::Player *>(videoView_->GetVideoPlayer());
256     if (videoPlayer == nullptr) {
257         return false;
258     }
259     videoPlayer->SetPlayerCallback(videoEventListener_);
260     videoView_->SetPlayEventListener(videoEventListener_);
261     return true;
262 }
263 
RegisterPrivateEventListener(uint16_t eventTypeId,jerry_value_t funcValue,bool isStopPropagation)264 bool VideoComponent::RegisterPrivateEventListener(uint16_t eventTypeId, jerry_value_t funcValue, bool isStopPropagation)
265 {
266     if (videoEventListener_ == nullptr || videoView_ == nullptr || videoSliderListener_ == nullptr) {
267         return false;
268     }
269     switch (eventTypeId) {
270         case K_ERROR:
271             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind ERROR callback function");
272             videoEventListener_->SetOnErrorFuncName(funcValue);
273             break;
274         case K_PREPARED:
275             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind PREPARED callback function");
276             videoView_->SetPrepareSyncCBFunc(funcValue);
277             break;
278         case K_START:
279             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind START callback function");
280             videoView_->SetStartSyncCBFunc(funcValue);
281             break;
282         case K_PAUSE:
283             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind PAUSE callback function");
284             videoView_->SetPauseSyncCBFunc(funcValue);
285             break;
286         case K_FINISH:
287             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind FINISH callback function");
288             videoEventListener_->SetOnPlayCompleteFuncName(funcValue);
289             break;
290         case K_SEEKING:
291             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind SEEKING callback function");
292             videoSliderListener_->SetOnPlaySeekingFuncName(funcValue);
293             break;
294         case K_SEEKED:
295             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind SEEKED callback function");
296             videoEventListener_->SetOnPlaySeekedFuncName(funcValue);
297             break;
298         case K_TIME_UPDATE:
299             HILOG_DEBUG(HILOG_MODULE_ACE, "VideoComponent: RegisterListener && bind TIME_UPDATE callback function");
300             videoView_->SetTimeUpdateSyncCBFunc(funcValue);
301             break;
302         default:
303             return false;
304     }
305     return true;
306 }
307 
SetPrivateAttribute(uint16_t attrKeyId,jerry_value_t attrValue)308 bool VideoComponent::SetPrivateAttribute(uint16_t attrKeyId, jerry_value_t attrValue)
309 {
310     switch (attrKeyId) {
311         case K_MUTED: {
312             SetMuted(attrValue);
313             break;
314         }
315         case K_SRC: {
316             SetVideoSource(attrValue);
317             break;
318         }
319         case K_AUTOPLAY: {
320             SetVideoAutoPlay(attrValue);
321             break;
322         }
323         case K_CONTROLS: {
324             SetVideoControls(attrValue);
325             break;
326         }
327         default: {
328             return false;
329         }
330     }
331     return true;
332 }
333 
SetMuted(jerry_value_t attrValue)334 void VideoComponent::SetMuted(jerry_value_t attrValue)
335 {
336     videoMuted_ = BoolOf(attrValue);
337     if (videoView_ != nullptr) {
338         videoView_->setMuted(videoMuted_);
339     }
340 }
341 
SetVideoSource(jerry_value_t attrValue)342 void VideoComponent::SetVideoSource(jerry_value_t attrValue)
343 {
344     ACE_FREE(videoSourceUrl_);
345     videoSourceUrl_ = MallocStringOf(attrValue);
346     if (videoView_ != nullptr) {
347         videoView_->SetVideoSrc(videoSourceUrl_);
348     }
349 }
350 
SetVideoAutoPlay(jerry_value_t attrValue)351 void VideoComponent::SetVideoAutoPlay(jerry_value_t attrValue)
352 {
353     autoPlay_ = BoolOf(attrValue);
354     if (videoView_ != nullptr) {
355         videoView_->SetAutoPlayFlag(autoPlay_);
356     }
357 }
358 
SetVideoControls(jerry_value_t attrValue)359 void VideoComponent::SetVideoControls(jerry_value_t attrValue)
360 {
361     if ((videoView_ != nullptr) && !BoolOf(attrValue)) {
362         videoView_->HideVideoPanel();
363     }
364 }
365 
ApplyPrivateStyle(const AppStyleItem * style)366 bool VideoComponent::ApplyPrivateStyle(const AppStyleItem *style)
367 {
368     return false;
369 }
370 
SetPanelView()371 bool VideoComponent::SetPanelView()
372 {
373     if (videoView_ == nullptr || videoPlayImageClickListener_ == nullptr) {
374         return false;
375     }
376     PanelView *panelView = const_cast<PanelView *>(videoView_->GetPanelView());
377     if (panelView == nullptr) {
378         return false;
379     }
380     /* set video total time and slider range */
381     int64_t totalPlayTime = 0;
382     if (videoView_->GetDuration(totalPlayTime) == 0) {
383         UISlider *slider = const_cast<UISlider *>(panelView->GetVideoSlider());
384         if (slider == nullptr || totalPlayTime < 0 || totalPlayTime >= PanelView::MAX_SHOW_TIME) {
385             return false;
386         }
387         slider->SetRange(totalPlayTime / PanelView::MILLIONS_PER_SECOND, 0);
388     }
389 
390     /* set panel info when autoPlay */
391     UIImageView *playImageView = const_cast<UIImageView *>(panelView->GetVideoPlayImage());
392     if (playImageView == nullptr) {
393         HILOG_ERROR(HILOG_MODULE_ACE, "video panel get play image view is nullptr");
394         return false;
395     }
396     // set total video time to total label
397     videoView_->UpdatePanelTimeText(false);
398     if (autoPlay_) {
399         if ((videoView_->Play()) == 0) {
400             playImageView->SetSrc(GetVideoPlayImageOffInfo());
401             videoPlayImageClickListener_->setVideoPlayImageClickStatus(true);
402         } else {
403             HILOG_ERROR(HILOG_MODULE_ACE, "video play failed");
404             return false;
405         }
406     } else {
407         playImageView->SetSrc(GetVideoPlayImageOnInfo());
408         videoPlayImageClickListener_->setVideoPlayImageClickStatus(false);
409     }
410     /* set video volume & panel muted image */
411     videoView_->UpdateMutedStatus();
412     videoPlayImageClickListener_->setVideoMutedImageClickStatus(videoMuted_);
413     videoView_->PanelRefreshLayout();
414     return true;
415 }
416 
OnViewAttached()417 void VideoComponent::OnViewAttached()
418 {
419     if (videoView_ == nullptr) {
420         return;
421     }
422     videoView_->SetVideoView();
423     if (videoView_->SetSource(videoSourceUrl_) != 0) {
424         HILOG_ERROR(HILOG_MODULE_ACE, "PostRender video view SetSource failed");
425         return;
426     }
427     if (videoView_->Prepare() != 0) {
428         HILOG_ERROR(HILOG_MODULE_ACE, "PostRender video view prepare failed");
429         return;
430     }
431     if (SetPanelView() == false) {
432         HILOG_ERROR(HILOG_MODULE_ACE, "PostRender set panel view failed");
433         return;
434     }
435 }
436 
PostUpdate(uint16_t attrKeyId)437 void VideoComponent::PostUpdate(uint16_t attrKeyId)
438 {
439     if (videoView_ == nullptr) {
440         HILOG_ERROR(HILOG_MODULE_ACE, "video component post update check args failed");
441         return;
442     }
443     videoView_->WaitRebuildPlayerFinish();
444     videoView_->SetVideoView();
445     if (!SetPanelView()) {
446         HILOG_ERROR(HILOG_MODULE_ACE, "PostUpdate set panel view failed");
447         return;
448     }
449 }
SetComponentReleasingFlag(bool releasing)450 void VideoComponent::SetComponentReleasingFlag(bool releasing)
451 {
452     isReleasing_ = releasing;
453 }
454 
455 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1)
PrepareProgressUpdatingThread()456 bool VideoComponent::PrepareProgressUpdatingThread()
457 {
458     int ret = pthread_mutex_init(&updateLock_, nullptr);
459     if (ret != 0) {
460         HILOG_ERROR(HILOG_MODULE_ACE, "mutex init failed, %{public}d", ret);
461         return false;
462     }
463     ret = pthread_cond_init(&updateCondition_, nullptr);
464     if (ret != 0) {
465         HILOG_ERROR(HILOG_MODULE_ACE, "condition init failed, %{public}d", ret);
466         (void)pthread_mutex_destroy(&updateLock_);
467         return false;
468     }
469     pthread_t tid;
470     pthread_attr_t attr;
471     pthread_attr_init(&attr);
472     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
473     ret = pthread_create(&tid, &attr, VideoComponent::UpdateProgressHandler, this);
474     if (ret != 0) {
475         HILOG_ERROR(HILOG_MODULE_ACE, "create video progress updating thread error, %{public}d", ret);
476         (void)pthread_mutex_destroy(&updateLock_);
477         (void)pthread_cond_destroy(&updateCondition_);
478         return false;
479     }
480     return true;
481 }
482 
UpdateProgress()483 void VideoComponent::UpdateProgress()
484 {
485     if (isReleasing_ || !(isPlaying_)) {
486         return;
487     }
488     if (videoView_ != nullptr) {
489         videoView_->UpdatePanelProgress();
490     }
491 }
492 
SetVideoPlayingFlag(bool playing)493 void VideoComponent::SetVideoPlayingFlag(bool playing)
494 {
495     isPlaying_ = playing;
496 }
497 
IsVideoPlaying() const498 bool VideoComponent::IsVideoPlaying() const
499 {
500     return isPlaying_;
501 }
502 
IsComponentReleasing() const503 bool VideoComponent::IsComponentReleasing() const
504 {
505     return isReleasing_;
506 }
507 
NotifyUpdatingThreadDestroy()508 void VideoComponent::NotifyUpdatingThreadDestroy()
509 {
510     (void)pthread_cond_destroy(&updateCondition_);
511     (void)pthread_mutex_destroy(&updateLock_);
512     isUpdatingHandlerQuited_ = true;
513 }
514 
AddComponentNode(Component * component)515 void VideoComponent::AddComponentNode(Component *component)
516 {
517     if (component == nullptr) {
518         return;
519     }
520     componentNodes_.PushBack(component);
521 }
522 
RemoveComponentNode(const Component * component)523 void VideoComponent::RemoveComponentNode(const Component *component)
524 {
525     if (component == nullptr) {
526         return;
527     }
528     ListNode<Component *> *node = componentNodes_.Begin();
529     while (node != componentNodes_.End()) {
530         if (node->data_ == component) {
531             componentNodes_.Remove(node);
532             break;
533         }
534         node = node->next_;
535     }
536 }
537 
ContainComponentNode(Component * component)538 bool VideoComponent::ContainComponentNode(Component *component)
539 {
540     if (component == nullptr) {
541         return false;
542     }
543     ListNode<Component *> *node = componentNodes_.Begin();
544     while (node != componentNodes_.End()) {
545         if (node->data_ == component) {
546             return true;
547         }
548         node = node->next_;
549     }
550     return false;
551 }
552 
OnPlayStateChanged(VideoPlayState newState)553 void VideoComponent::OnPlayStateChanged(VideoPlayState newState)
554 {
555     HILOG_INFO(HILOG_MODULE_ACE, "OnPlayStateChanged called newState[%{public}d]", newState);
556     int ret = pthread_mutex_lock(&updateLock_);
557     if (ret != 0) {
558         HILOG_ERROR(HILOG_MODULE_ACE, "mutex lock failed when playing state changed, %{public}d", ret);
559         return;
560     }
561     switch (newState) {
562         case VideoPlayState::STATE_PLAYING:
563             SetVideoPlayingFlag(true);
564             ret = pthread_cond_signal(&updateCondition_);
565             if (ret != 0) {
566                 HILOG_ERROR(HILOG_MODULE_ACE, "condition signal failed when playing state changed, %{public}d", ret);
567             }
568             break;
569         default:
570             SetVideoPlayingFlag(false);
571             break;
572     }
573     ret = pthread_mutex_unlock(&updateLock_);
574     if (ret != 0) {
575         HILOG_ERROR(HILOG_MODULE_ACE, "mutex unlock failed when playing state changed, %{public}d", ret);
576     }
577 }
578 
579 /* separated thread to trigger all update progress request */
UpdateProgressHandler(void * arg)580 void *VideoComponent::UpdateProgressHandler(void *arg)
581 {
582     prctl(PR_SET_NAME, "UpdateProgressHandler");
583     auto videoComponent = static_cast<VideoComponent *>(arg);
584     if (videoComponent == nullptr) {
585         HILOG_ERROR(HILOG_MODULE_ACE, "videoComponent is nullptr, fail to start loop");
586         return nullptr;
587     }
588 
589     HILOG_INFO(HILOG_MODULE_ACE, "start video progress updating loop");
590     while (!(videoComponent->IsComponentReleasing())) {
591         if (videoComponent->IsVideoPlaying()) {
592             auto task = [videoComponent]() {
593                 // critical case that the video component has been released but the task is already in queue
594                 if (!ContainComponentNode(videoComponent)) {
595                     return;
596                 }
597                 videoComponent->UpdateProgress();
598             };
599             HILOG_DEBUG(HILOG_MODULE_ACE, "video update progress");
600             AceAbility::PostUITask(task);
601             usleep(PanelView::UPDATE_CYCLE_MICRO_SECONDS); // request to update for every 250ms
602         } else {
603             // if the video is paused no need to post task
604             int ret = pthread_mutex_lock(&updateLock_);
605             if (ret != 0) {
606                 HILOG_ERROR(HILOG_MODULE_ACE, "mutex lock failed when updating progress, %{public}d", ret);
607                 break;
608             }
609             HILOG_INFO(HILOG_MODULE_ACE, "--- video panel update thread wating ----");
610             ret = pthread_cond_wait(&updateCondition_, &updateLock_);
611             if (ret != 0) {
612                 HILOG_ERROR(HILOG_MODULE_ACE, "condition wait failed when updating progress, %{public}d", ret);
613                 (void)pthread_mutex_unlock(&updateLock_);
614                 break;
615             }
616             ret = pthread_mutex_unlock(&updateLock_);
617             if (ret != 0) {
618                 HILOG_ERROR(HILOG_MODULE_ACE, "mutex unlock failed when updating progress, %{public}d", ret);
619                 break;
620             }
621         }
622     }
623     videoComponent->NotifyUpdatingThreadDestroy();
624     return nullptr;
625 }
626 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC
627 } // namespace ACELite
628 } // namespace OHOS
629 
630 #endif // FEATURE_COMPONENT_VIDEO
631