From b4d4e43753c973b8a21ff25d7afc59096ecec12c Mon Sep 17 00:00:00 2001 From: hw_ljz Date: Sat, 9 Nov 2024 17:52:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dvideo=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E9=BB=91=E5=B1=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hw_ljz --- .../pattern/video/video_pattern.cpp | 196 +++++++++++------- .../pattern/video/video_pattern.h | 34 ++- .../pattern/video/video_property_test_ng.cpp | 6 +- .../core/pattern/video/video_test_ng.cpp | 11 +- 4 files changed, 162 insertions(+), 85 deletions(-) diff --git a/frameworks/core/components_ng/pattern/video/video_pattern.cpp b/frameworks/core/components_ng/pattern/video/video_pattern.cpp index 3108bc5b578..09d8b31db5b 100755 --- a/frameworks/core/components_ng/pattern/video/video_pattern.cpp +++ b/frameworks/core/components_ng/pattern/video/video_pattern.cpp @@ -233,7 +233,8 @@ RectF AdjustPaintRect(float positionX, float positionY, float width, float heigh rect.SetHeight(nodeHeightI); return rect; } -Gradient ConvertToGradient(Color color) { +Gradient ConvertToGradient(Color color) +{ Gradient gradient; GradientColor gradientColorBegin; gradientColorBegin.SetLinearColor(LinearColor(color)); @@ -252,6 +253,16 @@ VideoPattern::VideoPattern(const RefPtr& videoController) : instanceId_(Container::CurrentId()), videoControllerV2_(videoController) {} +void VideoPattern::ResetInitializingPlayerTask() +{ + initializingTask_.Reset([weak = WeakClaim(this)]() { + auto video = weak.Upgrade(); + CHECK_NULL_VOID(video); + auto targetPattern = video->GetTargetVideoPattern(); + CHECK_NULL_VOID(targetPattern); + targetPattern->InitializeMediaPlayer(); + }); +} void VideoPattern::ResetStatus() { isInitialState_ = true; @@ -263,35 +274,74 @@ void VideoPattern::ResetStatus() void VideoPattern::ResetMediaPlayer(bool isResetByUser) { - if (mediaPlayer_ && !isPrepared_ && isResetByUser) { - PrepareMediaPlayer(); + if (isResetByUser && playerStatus_ == PlayerStatus::PREPARING) { return; } - ResetStatus(); + playerStatus_ = PlayerStatus::PREPARING; + ResetInitializingPlayerTask(); + initializingTask_(); + PrepareAsync(); +} + +void VideoPattern::InitializeMediaPlayer() +{ + CHECK_NULL_VOID(mediaPlayer_); mediaPlayer_->ResetMediaPlayer(); SetIsPrepared(false); if (!SetSourceForMediaPlayer()) { TAG_LOGW(AceLogTag::ACE_VIDEO, "Video set source for mediaPlayer failed."); - // It need post on ui thread. FireError(); + playerStatus_ = PlayerStatus::ERROR; return; } - RegisterMediaPlayerEvent(); - SetSurfaceForMediaPlayer(); - if (mediaPlayer_ && mediaPlayer_->PrepareAsync() != 0) { - TAG_LOGE(AceLogTag::ACE_VIDEO, "Player prepare failed"); + PrepareSurface(); + if (playerStatus_ == PlayerStatus::INITIALIZING) { + playerStatus_ = PlayerStatus::INITIALIZED; + } else if (playerStatus_ == PlayerStatus::RELEASING) { + playerStatus_ = PlayerStatus::RELEASED; } } +void VideoPattern::PrepareAsync() +{ + CHECK_NULL_VOID(mediaPlayer_); + if (playerStatus_ == PlayerStatus::ERROR) { + return; + } + if (initializingTask_.WaitUntilComplete(100ms)) { + if (mediaPlayer_->PrepareAsync() != 0) { + TAG_LOGE(AceLogTag::ACE_VIDEO, "Player prepare failed"); + } + } +} + +void VideoPattern::PrepareAsyncOnBg() +{ + if (playerStatus_ == PlayerStatus::ERROR) { + return; + } + ContainerScope scope(instanceId_); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto context = host->GetContext(); + CHECK_NULL_VOID(context); + auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND); + playerStatus_ = PlayerStatus::PREPARING; + platformTask.PostTask([weak = WeakClaim(this)] { + auto video = weak.Upgrade(); + CHECK_NULL_VOID(video); + auto targetPattern = video->GetTargetVideoPattern(); + CHECK_NULL_VOID(targetPattern); + targetPattern->PrepareAsync(); + }, "ArkUIVideoPrepareAsync"); +} + void VideoPattern::UpdateMediaPlayerOnBg() { - PrepareSurface(); RegisterVisibleRatioCallback(); - if (ShouldPrepareMediaPlayer()) { - PrepareMediaPlayer(); - } + PrepareMediaPlayer(); UpdateSpeed(); UpdateLooping(); UpdateMuted(); @@ -306,7 +356,6 @@ bool VideoPattern::IsVideoSourceChanged() auto videoLayoutProperty = GetLayoutProperty(); CHECK_NULL_RETURN(videoLayoutProperty, false); if (!videoLayoutProperty->HasVideoSource() || videoLayoutProperty->GetVideoSource() == videoSrcInfo_) { - TAG_LOGI(AceLogTag::ACE_VIDEO, "Video source is null or the source has not changed."); return false; } return true; @@ -316,10 +365,16 @@ void VideoPattern::PrepareMediaPlayer() auto videoLayoutProperty = GetLayoutProperty(); CHECK_NULL_VOID(videoLayoutProperty); // src has not set/changed - if (!videoLayoutProperty->HasVideoSource()) { - TAG_LOGI(AceLogTag::ACE_VIDEO, "Video source is null"); + if (!videoLayoutProperty->HasVideoSource() || videoLayoutProperty->GetVideoSource() == videoSrcInfo_) { + TAG_LOGI(AceLogTag::ACE_VIDEO, "Video source is null or the source has not changed."); return; } + if (playerStatus_ == PlayerStatus::PREPARING || playerStatus_ == PlayerStatus::INITIALIZING || + playerStatus_ == PlayerStatus::RELEASING) { + return; + } + isSeekingWhenNotPrepared_ = false; + auto shouldPreparePlayer = ShouldPrepareMediaPlayer(); auto videoSrcInfo = videoLayoutProperty->GetVideoSource(); videoSrcInfo_.src = videoSrcInfo->GetSrc(); videoSrcInfo_.bundleName = videoSrcInfo->GetBundleName(); @@ -327,13 +382,11 @@ void VideoPattern::PrepareMediaPlayer() if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) { mediaPlayer_->CreateMediaPlayer(); } - if (mediaPlayer_ && !mediaPlayer_->IsMediaPlayerValid()) { // It need post on ui thread. FireError(); return; } - ResetStatus(); ContainerScope scope(instanceId_); auto host = GetHost(); @@ -341,13 +394,20 @@ void VideoPattern::PrepareMediaPlayer() auto context = host->GetContext(); CHECK_NULL_VOID(context); auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND); - platformTask.PostTask([weak = WeakClaim(this)] { - auto video = weak.Upgrade(); - CHECK_NULL_VOID(video); - auto targetPattern = video->GetTargetVideoPattern(); - CHECK_NULL_VOID(targetPattern); - targetPattern->ResetMediaPlayer(); - }, "ArkUIVideoMediaPlayerReset"); + playerStatus_ = shouldPreparePlayer ? PlayerStatus::PREPARING : PlayerStatus::INITIALIZING; + if (shouldPreparePlayer) { + platformTask.PostTask([weak = WeakClaim(this)] { + auto video = weak.Upgrade(); + CHECK_NULL_VOID(video); + auto targetPattern = video->GetTargetVideoPattern(); + CHECK_NULL_VOID(targetPattern); + targetPattern->ResetMediaPlayer(); + }, "ArkUIVideoResetMediaPlayer"); + } + else { + ResetInitializingPlayerTask(); + platformTask.PostTask(initializingTask_, "ArkUIVideoInitializingTask"); + } } bool VideoPattern::SetSourceForMediaPlayer() @@ -425,7 +485,6 @@ void VideoPattern::RegisterMediaPlayerEvent() auto video = videoPattern.Upgrade(); CHECK_NULL_VOID(video); ContainerScope scope(video->instanceId_); - video->SetIsRequestMediaPlayerBySeek(false); video->SetIsSeeking(false); video->OnCurrentTimeChange(currentPos); }, @@ -538,10 +597,6 @@ void VideoPattern::ChangePlayerStatus(bool isPlaying, const PlaybackStatus& stat eventHub->FireStartEvent(param); } - if (status == PlaybackStatus::IDLE) { - SetIsPrepared(false); - isReleasingMediaPlayer_ = false; - } if (status == PlaybackStatus::PAUSED) { auto json = JsonUtil::Create(true); json->Put("pause", ""); @@ -601,6 +656,7 @@ void VideoPattern::OnPlayerStatus(PlaybackStatus status) void VideoPattern::OnError(const std::string& errorId) { + playerStatus_ = PlayerStatus::ERROR; isStartByUser_ = false; SetIsPrepared(false); std::string errorcode = Localization::GetInstance()->GetErrorDescription(errorId); @@ -667,11 +723,11 @@ void VideoPattern::OnPrepared(uint32_t duration, uint32_t currentPos, bool needF isPlaying_ = mediaPlayer_->IsPlaying(); SetIsSeeking(false); SetIsPrepared(true); + playerStatus_ = PlayerStatus::PREPARED; + UpdateControlBar(duration_, true); OnUpdateTime(duration_, DURATION_POS); OnUpdateTime(currentPos_, CURRENT_POS); - UpdateControlBar(duration_, true); - if (needFireEvent) { auto json = JsonUtil::Create(true); json->Put("duration", static_cast(duration_)); @@ -841,6 +897,7 @@ void VideoPattern::OnUpdateTime(uint32_t time, int pos) const void VideoPattern::PrepareSurface() { + CHECK_NULL_VOID(mediaPlayer_); if (renderSurface_->IsSurfaceValid()) { return; } @@ -848,14 +905,6 @@ void VideoPattern::PrepareSurface() renderSurface_->SetRenderContext(renderContextForMediaPlayer_); } renderSurface_->InitSurface(); -} - -void VideoPattern::SetSurfaceForMediaPlayer() -{ - if (!mediaPlayer_ || !renderSurface_->IsSurfaceValid() || isSetMediaSurfaceDone_) { - return; - } - isSetMediaSurfaceDone_ = true; mediaPlayer_->SetRenderSurface(renderSurface_); if (mediaPlayer_->SetSurface() != 0) { TAG_LOGW(AceLogTag::ACE_VIDEO, "mediaPlayer renderSurface set failed"); @@ -1575,11 +1624,15 @@ void VideoPattern::SetMethodCall() void VideoPattern::Start() { CHECK_NULL_VOID(mediaPlayer_); - if (!isPrepared_) { - PrepareMediaPlayer(); + if (playerStatus_ == PlayerStatus::PREPARING) { isStartByUser_ = true; return; } + if (playerStatus_ != PlayerStatus::PREPARED) { + isStartByUser_ = true; + PrepareAsyncOnBg(); + return; + } StartPlay(); } @@ -1625,9 +1678,14 @@ void VideoPattern::Pause() void VideoPattern::Stop() { - if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid() || isRequestMediaPlayerBySeek_) { + if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) { return; } + if (playerStatus_ == PlayerStatus::PREPARED) { + playerStatus_ = PlayerStatus::RELEASING; + } + isStartByUser_ = false; + isSeekingWhenNotPrepared_ = false; OnCurrentTimeChange(0); mediaPlayer_->Stop(); isStop_ = true; @@ -1727,13 +1785,16 @@ void VideoPattern::ChangeFullScreenButtonTag(bool isFullScreen, RefPtr& videoPattern) ChangePlayButtonTag(); } isInitialState_ = videoPattern->GetInitialState(); - auto videoSrcInfo = videoPattern->GetVideoSource(); - videoSrcInfo_.src = videoSrcInfo.GetSrc(); - videoSrcInfo_.bundleName = videoSrcInfo.GetBundleName(); - videoSrcInfo_.moduleName = videoSrcInfo.GetModuleName(); + auto layoutProperty = videoPattern->GetLayoutProperty(); + auto videoSrcInfo = layoutProperty->GetVideoSource(); + videoSrcInfo_.src = videoSrcInfo->GetSrc(); + videoSrcInfo_.bundleName = videoSrcInfo->GetBundleName(); + videoSrcInfo_.moduleName = videoSrcInfo->GetModuleName(); isPrepared_ = videoPattern->GetIsPrepared(); isSeeking_ = videoPattern->GetIsSeeking(); isStop_ = videoPattern->GetIsStop(); @@ -1934,6 +1991,8 @@ void VideoPattern::RecoverState(const RefPtr& videoPattern) seekingPosWhenNotPrepared_ = videoPattern->GetSeekingPosWhenNotPrepared(); seekingModeWhenNotPrepared_ = videoPattern->GetSeekingModeWhenNotPrepared(); isSeeking_ = videoPattern->GetIsSeeking(); + playerStatus_ = videoPattern->GetPlayerStatus(); + initializingTask_ = std::move(videoPattern->GetInitializingTask()); UpdateControlBar(duration_); RegisterMediaPlayerEvent(); auto videoNode = GetHost(); @@ -2214,8 +2273,9 @@ void VideoPattern::RegisterVisibleRatioCallback() auto pattern = weak.Upgrade(); CHECK_NULL_VOID(pattern); if (isVisible && currentRatio >= 0.0) { - if (!pattern->GetIsPrepared() && (!pattern->GetIsStop() || pattern->IsVideoSourceChanged())) { - pattern->PrepareMediaPlayer(); + auto playerStatus = pattern->GetPlayerStatus(); + if (playerStatus == PlayerStatus::INITIALIZED) { + pattern->PrepareAsyncOnBg(); } pattern->UpdateVisibility(true); } @@ -2225,7 +2285,7 @@ void VideoPattern::RegisterVisibleRatioCallback() }; auto pipeline = host->GetContext(); CHECK_NULL_VOID(pipeline); - pipeline->AddVisibleAreaChangeNode(host, {0.0, 1.0}, visibleAreaChangeFunc, false); + pipeline->AddVisibleAreaChangeNode(host, {0.0}, visibleAreaChangeFunc, false); } void VideoPattern::RecordSeekingInfoBeforePlaying(float currentPos, OHOS::Ace::SeekMode seekMode, bool sliderChange) @@ -2237,30 +2297,24 @@ void VideoPattern::RecordSeekingInfoBeforePlaying(float currentPos, OHOS::Ace::S void VideoPattern::ReleaseMediaPlayer() { - isSetMediaSurfaceDone_ = false; - isStartByUser_ = false; - isSeekingWhenNotPrepared_ = false; - isReleasingMediaPlayer_ = true; + playerStatus_ = PlayerStatus::RELEASING; ContainerScope scope(instanceId_); auto context = PipelineContext::GetCurrentContext(); CHECK_NULL_VOID(context); auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND); - platformTask.PostTask([weak = WeakClaim(RawPtr(mediaPlayer_))] { - auto mediaPlayer = weak.Upgrade(); - CHECK_NULL_VOID(mediaPlayer && mediaPlayer->IsMediaPlayerValid()); - mediaPlayer->ResetMediaPlayer(); - }, "ArkUIVideoResetMediaPlayer"); + ResetInitializingPlayerTask(); + platformTask.PostTask(initializingTask_, "ArkUIVideoReleasingMediaPlayer"); } bool VideoPattern::ShouldPrepareMediaPlayer() { CHECK_NULL_RETURN(mediaPlayer_, false); - if (isPrepared_) { + if (playerStatus_ == PlayerStatus::PREPARED) { return IsVideoSourceChanged(); } auto layoutProperty = GetLayoutProperty(); if (layoutProperty && layoutProperty->HasVisibility()) { - return true; + return IsVideoSourceChanged(); } return isVisible_ && IsVideoSourceChanged(); } diff --git a/frameworks/core/components_ng/pattern/video/video_pattern.h b/frameworks/core/components_ng/pattern/video/video_pattern.h index 2b0ca905607..8d8eb07b5a3 100755 --- a/frameworks/core/components_ng/pattern/video/video_pattern.h +++ b/frameworks/core/components_ng/pattern/video/video_pattern.h @@ -36,6 +36,16 @@ namespace OHOS::Ace { class ImageAnalyzerManager; } namespace OHOS::Ace::NG { +enum class PlayerStatus { + NONE, + ERROR, + INITIALIZING, + INITIALIZED, + PREPARING, + PREPARED, + RELEASING, + RELEASED, +}; class VideoPattern : public Pattern { DECLARE_ACE_TYPE(VideoPattern, Pattern); @@ -285,9 +295,20 @@ public: { return videoSrcInfo_; } - void SetIsRequestMediaPlayerBySeek(bool isRequestMediaPlayerBySeek) + void PrepareAsyncOnBg(); + PlayerStatus GetPlayerStatus() { - isRequestMediaPlayerBySeek_ = isRequestMediaPlayerBySeek; + return playerStatus_; + } + void SetTargetPlayerStatus(PlayerStatus playerStatus) + { + playerStatus_ = playerStatus; + } + void InitializeMediaPlayer(); + void PrepareAsync(); + CancelableCallback GetInitializingTask() + { + return initializingTask_; } #ifdef RENDER_EXTRACT_SUPPORTED void OnTextureRefresh(void* surface); @@ -406,7 +427,6 @@ private: void UpdateOverlayVisibility(VisibleType type); void UpdateControlBar(uint32_t duration, bool isChangePlayBtn = false); - void SetSurfaceForMediaPlayer(); void StartPlay(); void SeekTo(float currentPos, OHOS::Ace::SeekMode seekMode); bool IsVideoSourceChanged(); @@ -414,8 +434,7 @@ private: void RegisterVisibleRatioCallback(); void ReleaseMediaPlayer(); bool ShouldPrepareMediaPlayer(); - void UpdatePlayingFlags(); - void CleanPlayingFlags(); + void ResetInitializingPlayerTask(); RefPtr videoControllerV2_; RefPtr controlBar_; @@ -461,11 +480,10 @@ private: bool isSeekingWhenNotPrepared_ = false; uint32_t seekingPosWhenNotPrepared_ = 0; SeekMode seekingModeWhenNotPrepared_ = SeekMode::SEEK_CLOSEST; - bool isSetMediaSurfaceDone_ = false; bool isStartByUser_ = false; bool isVisible_ = false; - bool isRequestMediaPlayerBySeek_ = false; - bool isReleasingMediaPlayer_ = false; + PlayerStatus playerStatus_ = PlayerStatus::NONE; + CancelableCallback initializingTask_; ACE_DISALLOW_COPY_AND_MOVE(VideoPattern); }; } // namespace OHOS::Ace::NG diff --git a/test/unittest/core/pattern/video/video_property_test_ng.cpp b/test/unittest/core/pattern/video/video_property_test_ng.cpp index 3f7398a9d64..bf73754b9f2 100644 --- a/test/unittest/core/pattern/video/video_property_test_ng.cpp +++ b/test/unittest/core/pattern/video/video_property_test_ng.cpp @@ -992,7 +992,7 @@ HWTEST_F(VideoPropertyTestNg, VideoPatternTest022, TestSize.Level1) .WillRepeatedly(Return(true)); EXPECT_CALL(*(AceType::DynamicCast(videoPattern->mediaPlayer_)), PrepareAsync()) .WillOnce(Return(-1)); - videoPattern->isPrepared_ = true; + videoPattern->playerStatus_ = PlayerStatus::PREPARED; videoPattern->isStop_ = true; videoPattern->isInitialState_ = false; videoPattern->UpdateMediaPlayerOnBg(); @@ -1108,7 +1108,7 @@ HWTEST_F(VideoPropertyTestNg, VideoPatternTest025, TestSize.Level1) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(*(AceType::DynamicCast(videoPattern->mediaPlayer_)), SetSurface()) - .Times(0); + .WillOnce(Return(-1)); videoPattern->PrepareSurface(); SystemProperties::SetExtSurfaceEnabled(false); videoPattern->PrepareSurface(); @@ -1222,7 +1222,7 @@ HWTEST_F(VideoPropertyTestNg, VideoPatternTest028, TestSize.Level1) .WillOnce(Return(-1)); EXPECT_CALL(*(AceType::DynamicCast(videoPattern->mediaPlayer_)), IsMediaPlayerValid()) .WillRepeatedly(Return(true)); - videoPattern->isPrepared_ = true; + videoPattern->playerStatus_ = PlayerStatus::PREPARED; videoPattern->isInitialState_ = false; videoPattern->autoPlay_ = false; videoPattern->UpdateVideoProperty(); diff --git a/test/unittest/core/pattern/video/video_test_ng.cpp b/test/unittest/core/pattern/video/video_test_ng.cpp index e7bae84f223..d393482a4c1 100644 --- a/test/unittest/core/pattern/video/video_test_ng.cpp +++ b/test/unittest/core/pattern/video/video_test_ng.cpp @@ -314,7 +314,7 @@ HWTEST_F(VideoTestNg, VideoPatternTest008, TestSize.Level1) .Times(3) .WillRepeatedly(Return(true)); pattern->UpdateMediaPlayerOnBg(); - + pattern->playerStatus_ = PlayerStatus::PREPARED; /** * @tc.steps: step4. Call UpdateMediaPlayerOnBg * case: IsMediaPlayerValid is always true & has set VideoSource @@ -329,7 +329,7 @@ HWTEST_F(VideoTestNg, VideoPatternTest008, TestSize.Level1) .WillRepeatedly(Return(true)); pattern->UpdateMediaPlayerOnBg(); - + pattern->playerStatus_ = PlayerStatus::PREPARED; /** * @tc.steps: step5. Call UpdateMediaPlayerOnBg * case: IsMediaPlayerValid is always true & has set VideoSource & has set videoSrcInfo_.src @@ -339,6 +339,7 @@ HWTEST_F(VideoTestNg, VideoPatternTest008, TestSize.Level1) .Times(3) .WillRepeatedly(Return(true)); pattern->UpdateMediaPlayerOnBg(); + pattern->playerStatus_ = PlayerStatus::PREPARED; /** * @tc.steps: step6. Call UpdateMediaPlayerOnBg @@ -357,6 +358,7 @@ HWTEST_F(VideoTestNg, VideoPatternTest008, TestSize.Level1) .WillOnce(Return(true)); pattern->UpdateMediaPlayerOnBg(); + pattern->playerStatus_ = PlayerStatus::PREPARED; /** * @tc.steps: step7. Call UpdateMediaPlayerOnBg several times @@ -387,10 +389,13 @@ HWTEST_F(VideoTestNg, VideoPatternTest008, TestSize.Level1) .WillOnce(Return(true)); pattern->videoSrcInfo_.src.clear(); pattern->UpdateMediaPlayerOnBg(); + pattern->playerStatus_ = PlayerStatus::PREPARED; pattern->videoSrcInfo_.src.clear(); pattern->UpdateMediaPlayerOnBg(); + pattern->playerStatus_ = PlayerStatus::PREPARED; pattern->videoSrcInfo_.src.clear(); pattern->UpdateMediaPlayerOnBg(); + pattern->playerStatus_ = PlayerStatus::PREPARED; // CreateMediaPlayer success but PrepareMediaPlayer fail for mediaPlayer is invalid EXPECT_CALL(*(AceType::DynamicCast(pattern->mediaPlayer_)), IsMediaPlayerValid()) @@ -661,7 +666,7 @@ HWTEST_F(VideoTestNg, VideoPatternTest012, TestSize.Level1) for (bool isStop : isStops) { for (int prepareReturn : prepareReturns) { pattern->isStop_ = isStop; - pattern->isPrepared_ = true; + pattern->playerStatus_ = PlayerStatus::PREPARED; if (isStop) { EXPECT_CALL(*(AceType::DynamicCast(pattern->mediaPlayer_)), PrepareAsync()) .WillOnce(Return(prepareReturn));