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 #ifndef OHOS_ACELITE_VIDEO_COMPONENT_H
16 #define OHOS_ACELITE_VIDEO_COMPONENT_H
17 
18 #include "acelite_config.h"
19 #if (FEATURE_COMPONENT_VIDEO == 1)
20 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1)
21 #include <pthread.h>
22 #include <unistd.h>
23 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC
24 #include "component.h"
25 #include "gfx_utils/list.h"
26 #include "panel_view.h"
27 #include "video_state_callback.h"
28 #include "video_view.h"
29 
30 namespace OHOS {
31 namespace ACELite {
32 class VideoPlayImageOnClickListener final : public UIView::OnClickListener {
33 public:
34     ACE_DISALLOW_COPY_AND_MOVE(VideoPlayImageOnClickListener);
VideoPlayImageOnClickListener(VideoView * aceVideo)35     explicit VideoPlayImageOnClickListener(VideoView *aceVideo)
36         : video_(aceVideo),
37           videoPlayImageClick_(false),
38           videoMutedImageClick_(false) {}
~VideoPlayImageOnClickListener()39     ~VideoPlayImageOnClickListener() {}
OnClick(UIView & view,const ClickEvent & event)40     bool OnClick(UIView &view, const ClickEvent &event) override
41     {
42         if (video_ == nullptr) {
43             return false;
44         }
45         UIImageView *image = reinterpret_cast<UIImageView *>(&view);
46         if (image == nullptr) {
47             return false;
48         }
49         PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView());
50         if (panelView == nullptr) {
51             return false;
52         }
53         UIImageView* playImage = const_cast<UIImageView *>(panelView->GetVideoPlayImage());
54         if (playImage != nullptr && playImage == image) {
55             if (SetPlayImageInfo(playImage) == false) {
56                 HILOG_ERROR(HILOG_MODULE_ACE, "set play image info failed.");
57                 return false;
58             }
59         }
60 
61         UIImageView* mutedImage = const_cast<UIImageView *>(panelView->GetVideoMutedImage());
62         if (mutedImage != nullptr && mutedImage == image) {
63             if (SetMutedImageInfo(mutedImage) == false) {
64                 HILOG_ERROR(HILOG_MODULE_ACE, "set muted image info failed.");
65                 return false;
66             }
67         }
68         video_->PanelRefreshLayout();
69         return true;
70     }
71 
SetPlayImageInfo(UIImageView * playImage)72     bool SetPlayImageInfo(UIImageView* playImage)
73     {
74         if (video_ == nullptr || playImage == nullptr) {
75             return false;
76         }
77         if (videoPlayImageClick_) {
78             if ((video_->Pause()) == 0) {
79                 playImage->SetSrc(GetVideoPlayImageOnInfo());
80                 videoPlayImageClick_ = false;
81                 return true;
82             }
83         } else {
84             if ((video_->Play()) == 0) {
85                 playImage->SetSrc(GetVideoPlayImageOffInfo());
86                 videoPlayImageClick_ = true;
87                 return true;
88             }
89         }
90         return false;
91     }
92 
SetMutedImageInfo(UIImageView * mutedImage)93     bool SetMutedImageInfo(UIImageView* mutedImage)
94     {
95         if (video_ == nullptr || mutedImage == nullptr) {
96             return false;
97         }
98         if (videoMutedImageClick_) {
99             if (video_->SetVolume(PanelView::DEFAULT_VOLUME_VALUE) == 0) {
100                 mutedImage->SetSrc(GetVideoMutedImageOnInfo());
101                 videoMutedImageClick_ = false;
102                 return true;
103             }
104         } else {
105             if (video_->SetVolume(0) == 0) {
106                 mutedImage->SetSrc(GetVideoMutedImageOffInfo());
107                 video_->setMuted(true);
108                 videoMutedImageClick_ = true;
109                 return true;
110             }
111         }
112         return false;
113     }
114 
setVideoPlayImageClickStatus(bool status)115     bool setVideoPlayImageClickStatus(bool status)
116     {
117         videoPlayImageClick_ = status;
118         return true;
119     }
120 
setVideoMutedImageClickStatus(bool status)121     bool setVideoMutedImageClickStatus(bool status)
122     {
123         videoMutedImageClick_ = status;
124         return true;
125     }
126 
127 private:
128     VideoView* video_;
129     bool videoPlayImageClick_;
130     bool videoMutedImageClick_;
131 };
132 
133 class VideoSliderEventListener final: public UISlider::UISliderEventListener, public UISlider::OnClickListener {
134 public:
135     ACE_DISALLOW_COPY_AND_MOVE(VideoSliderEventListener);
VideoSliderEventListener(VideoView * aceVideo)136     explicit VideoSliderEventListener(VideoView *aceVideo)
137         : video_(aceVideo), playSeekingFunc_(UNDEFINED), progressValue_(0) {}
~VideoSliderEventListener()138     ~VideoSliderEventListener()
139     {
140         ReleaseJerryValue(playSeekingFunc_, VA_ARG_END_FLAG);
141     }
142 
OnChange(int32_t progress)143     void OnChange(int32_t progress) override
144     {
145         if (video_ == nullptr) {
146             return;
147         }
148         progressValue_ = progress;
149         Media::Player* videoPlayer = const_cast<Media::Player *>(video_->GetPlayer());
150         if (videoPlayer != nullptr && videoPlayer->IsPlaying()) {
151             // when slider changing && videoPlayer is playing, notify UpdateProgressHandler stop update
152             video_->UpdatePlayState(VideoPlayState::STATE_STOPPED);
153         }
154         video_->SetCurrentPlayTimeText(progress);
155         video_->PanelRefreshLayout();
156         // call js registered on seeking function
157         if (!jerry_value_is_function(playSeekingFunc_)) {
158             return;
159         }
160         video_->CallJSFunctionWithOnePara(playSeekingFunc_, progress);
161     }
162 
OnClick(UIView & view,const ClickEvent & event)163     bool OnClick(UIView &view, const ClickEvent& event) override
164     {
165         if (SetPlayPositionInfo(progressValue_)) {
166             HILOG_DEBUG(HILOG_MODULE_ACE, "slider onClick video to %{public}d", progressValue_);
167             return true;
168         }
169         return false;
170     }
OnRelease(int32_t progress)171     void OnRelease(int32_t progress) override
172     {
173         if (SetPlayPositionInfo(progress)) {
174             HILOG_DEBUG(HILOG_MODULE_ACE, "slider release video to %{public}d", progress);
175         }
176     }
177 
SetPlayPositionInfo(int32_t progressValue)178     bool SetPlayPositionInfo(int32_t progressValue)
179     {
180         if (video_ == nullptr) {
181             return false;
182         }
183         int64_t playPosition = progressValue * PanelView::MILLIONS_PER_SECOND;
184         if (video_->SeekTo(playPosition) == 0) {
185             video_->SetCurrentPlayTimeText(progressValue);
186             video_->PanelRefreshLayout();
187             Media::Player* videoPlayer = const_cast<Media::Player *>(video_->GetPlayer());
188             if (videoPlayer != nullptr && videoPlayer->IsPlaying()) {
189                 // when slider clicked && videoPlayer is playing, notify UpdateProgressHandler start update
190                 video_->UpdatePlayState(VideoPlayState::STATE_PLAYING);
191             }
192         }
193         return true;
194     }
195 
SetOnPlaySeekingFuncName(jerry_value_t bindFunc)196     void SetOnPlaySeekingFuncName(jerry_value_t bindFunc)
197     {
198         playSeekingFunc_ = jerry_acquire_value(bindFunc);
199     }
200 private:
201     VideoView* video_;
202     jerry_value_t playSeekingFunc_;
203     int32_t progressValue_;
204 };
205 
206 class VideoEventListener final: public OHOS::Media::PlayerCallback {
207 public:
208     ACE_DISALLOW_COPY_AND_MOVE(VideoEventListener);
VideoEventListener(VideoView * aceVideo,VideoPlayImageOnClickListener * imageClickListener)209     VideoEventListener(VideoView *aceVideo, VideoPlayImageOnClickListener *imageClickListener)
210         : playErrorFunc_(UNDEFINED),
211           playCompleteFunc_(UNDEFINED),
212           playSeekedFunc_(UNDEFINED),
213           video_(aceVideo),
214           playImageListener_(imageClickListener) {}
215 
~VideoEventListener()216     ~VideoEventListener()
217     {
218         ReleaseJerryValue(playErrorFunc_, playCompleteFunc_, playSeekedFunc_, VA_ARG_END_FLAG);
219     }
OnError(int32_t errorType,int32_t errorCode)220     void OnError(int32_t errorType, int32_t errorCode) override
221     {
222         if (video_ == nullptr) {
223             return;
224         }
225         video_->UpdatePlayState(VideoPlayState::STATE_STOPPED);
226         if (jerry_value_is_function(playErrorFunc_)) {
227             CallJSFunctionAutoRelease(playErrorFunc_, UNDEFINED, nullptr, 0);
228         }
229         HILOG_DEBUG(HILOG_MODULE_ACE, "video play errorType = %{public}d, errCode= %{public}d", errorType, errorCode);
230     }
231 
OnPlaybackComplete()232     void OnPlaybackComplete() override
233     {
234         if (video_ == nullptr) {
235             return;
236         }
237         video_->UpdatePlayState(VideoPlayState::STATE_STOPPED);
238         video_->PrepareRebuildPlayerThread();
239         // call js complete function
240         if (jerry_value_is_function(playCompleteFunc_)) {
241             CallJSFunctionAutoRelease(playCompleteFunc_, UNDEFINED, nullptr, 0);
242         }
243         // update play image when video play complete
244         PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView());
245         if (panelView == nullptr) {
246             return;
247         }
248         UIImageView* playImage = const_cast<UIImageView *>(panelView->GetVideoPlayImage());
249         if (playImage == nullptr || playImageListener_ == nullptr) {
250             return;
251         }
252         playImage->SetSrc(GetVideoPlayImageOnInfo());
253         playImageListener_->setVideoPlayImageClickStatus(false);
254         video_->PanelRefreshLayout();
255         HILOG_DEBUG(HILOG_MODULE_ACE, "video play complete.");
256     }
257 
OnInfo(int type,int extra)258     void OnInfo(int type, int extra) override
259     {
260         HILOG_DEBUG(HILOG_MODULE_ACE, "video play on Info. type= %{public}d, extra= %{public}d", type, extra);
261     }
262 
OnVideoSizeChanged(int width,int height)263     void OnVideoSizeChanged(int width, int height) override
264     {
265         HILOG_DEBUG(HILOG_MODULE_ACE, "Video Size Changed. width= %{public}d, height= %{public}d", width, height);
266     }
267 
OnRewindToComplete()268     void OnRewindToComplete() override
269     {
270         if (video_ == nullptr) {
271             return;
272         }
273         PanelView* panelView = const_cast<PanelView *>(video_->GetPanelView());
274         if (panelView == nullptr) {
275             return;
276         }
277         const UISlider* slider = panelView->GetVideoSlider();
278         if (slider == nullptr) {
279             return;
280         }
281         int16_t sliderValue = slider->GetValue();
282         if (!jerry_value_is_function(playSeekedFunc_)) {
283             return;
284         }
285         video_->CallJSFunctionWithOnePara(playSeekedFunc_, sliderValue);
286         HILOG_DEBUG(HILOG_MODULE_ACE, "video seek to play complete.");
287     }
288 
SetOnErrorFuncName(jerry_value_t bindFunc)289     void SetOnErrorFuncName(jerry_value_t bindFunc)
290     {
291         playErrorFunc_ = jerry_acquire_value(bindFunc);
292     }
293 
SetOnPlayCompleteFuncName(jerry_value_t bindFunc)294     void SetOnPlayCompleteFuncName(jerry_value_t bindFunc)
295     {
296         playCompleteFunc_ = jerry_acquire_value(bindFunc);
297     }
298 
SetOnPlaySeekedFuncName(jerry_value_t bindFunc)299     void SetOnPlaySeekedFuncName(jerry_value_t bindFunc)
300     {
301         playSeekedFunc_ = jerry_acquire_value(bindFunc);
302     }
303 
304 private:
305     jerry_value_t playErrorFunc_;
306     jerry_value_t playCompleteFunc_;
307     jerry_value_t playSeekedFunc_;
308     VideoView* video_;
309     VideoPlayImageOnClickListener* playImageListener_;
310 };
311 
312 class VideoComponent : public Component, public VideoStateCallback {
313 public:
314     ACE_DISALLOW_COPY_AND_MOVE(VideoComponent);
315     VideoComponent(jerry_value_t options, jerry_value_t children, AppStyleManager* styleManager);
~VideoComponent()316     ~VideoComponent() override {}
317     void OnPlayStateChanged(VideoPlayState newState) override;
318 
319 protected:
320     bool CreateNativeViews() override;
321     void ReleaseNativeViews() override;
322     UIView *GetComponentRootView() const override;
323     bool SetPrivateAttribute(uint16_t attrKeyId, jerry_value_t attrValue) override;
324     bool ApplyPrivateStyle(const AppStyleItem* style) override;
325     void OnViewAttached() override;
326     void PostUpdate(uint16_t attrKeyId) override;
327     bool RegisterPrivateEventListener(uint16_t eventTypeId, jerry_value_t funcValue, bool isStopPropagation) override;
328 
329     static List<Component *> componentNodes_;
330 
331 private:
332     bool SetPanelView();
333     void SetMuted(jerry_value_t attrValue);
334     void SetVideoSource(jerry_value_t attrValue);
335     void SetVideoAutoPlay(jerry_value_t attrValue);
336     void SetVideoControls(jerry_value_t attrValue);
337     void RegisterNativeFunctions();
338     bool RegisterVideoEventListener();
339     bool PrepareProgressUpdatingThread();
340     void UpdatePlayImageInfo(bool playFlag);
341     void UpdateProgress();
342     void SetVideoPlayingFlag(bool playing);
343     void SetComponentReleasingFlag(bool releasing);
344     bool IsComponentReleasing() const;
345     bool IsVideoPlaying() const;
346     void NotifyUpdatingThreadDestroy();
347     static void AddComponentNode(Component *component);
348     static void RemoveComponentNode(const Component *component);
349     static bool ContainComponentNode(Component *component);
350     static void VideoStateCallback(VideoPlayState state);
351     static void *UpdateProgressHandler(void *arg);
352 
353     static JSValue Start(const jerry_value_t func,
354                          const jerry_value_t context,
355                          const jerry_value_t args[],
356                          const jerry_length_t argsNum);
357     static JSValue Pause(const jerry_value_t func,
358                          const jerry_value_t context,
359                          const jerry_value_t args[],
360                          const jerry_length_t argsNum);
361     static JSValue SetCurrentTime(const jerry_value_t func,
362                                   const jerry_value_t context,
363                                   const jerry_value_t args[],
364                                   const jerry_length_t argsNum);
365 
366     static JSValue SetVolume(const jerry_value_t func,
367                              const jerry_value_t context,
368                              const jerry_value_t args[],
369                              const jerry_length_t argsNum);
370 
371     static const char * const FUNC_START;
372     static const char * const FUNC_PAUSE;
373     static const char * const FUNC_SET_CURRENT_TIME;
374     static const char * const FUNC_SET_Volume;
375 
376     char* videoSourceUrl_;
377     VideoView* videoView_;
378     std::shared_ptr<VideoEventListener> videoEventListener_;
379     VideoSliderEventListener* videoSliderListener_;
380     VideoPlayImageOnClickListener* videoPlayImageClickListener_;
381     bool autoPlay_;
382     bool videoMuted_;
383     bool isPlaying_;
384     bool isReleasing_;
385     bool isUpdatingHandlerQuited_;
386 #if (FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC == 1)
387     static pthread_mutex_t updateLock_;
388     static pthread_cond_t updateCondition_;
389 #endif // FEATURE_UPDATE_VIDEO_PROGRESS_ASYNC
390 };
391 } // namespace ACELite
392 } // namespace OHOS
393 #endif // FEATURE_COMPONENT_VIDEO
394 #endif // OHOS_ACELITE_VIDEO_COMPONENT_H
395