virtual void SetActiveAudioTrack(int index) = 0;
virtual void SetActiveVideoTrack(int index) = 0;
virtual void SetPreferTextLanguage(const std::string& lang) = 0;
+ virtual void DestroyPlayerSync(base::OnceClosure cb) = 0;
#endif
};
void SetActiveAudioTrack(int index);
void SetActiveVideoTrack(int index);
void SetPreferTextLanguage(const std::string& lang);
+ void DestroyPlayerSync(base::OnceClosure cb);
#endif
// |enabled_track_ids| contains track ids of enabled audio tracks.
#if BUILDFLAG(IS_TIZEN_TV)
void NotifyTrackInfoToBrowser(int active_track_id) final;
void AddTrackInfo(media::MediaTrackInfo trackinfo);
+ void PlayerDestroyed();
#endif
void OnBufferingStateChange(BufferingState state,
BufferingStateChangeReason reason) final;
#if BUILDFLAG(IS_TIZEN_TV)
std::string mime_type_;
std::unique_ptr<DecryptingMediaResource> decrypting_media_resource_{nullptr};
+ base::OnceClosure player_destroy_cb_;
#endif
// Whether we've received the audio/video ended events.
base::BindRepeating(&RendererWrapper::OnWaiting,
weak_factory_.GetWeakPtr()));
}
+void PipelineImpl::RendererWrapper::DestroyPlayerSync(base::OnceClosure cb) {
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") ;" << __func__;
+
+ // If we destory during starting/seeking/suspending/resuming we don't want to
+ // leave outstanding callbacks around
+ pending_callbacks_.reset();
+
+ player_destroy_cb_ = std::move(cb);
+ if (shared_state_.renderer) {
+ shared_state_.renderer->DestroyPlayerSync(base::BindOnce(
+ &RendererWrapper::PlayerDestroyed, weak_factory_.GetWeakPtr()));
+ } else {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") ;" << __func__
+ << ", shared_state_.renderer is null";
+ std::move(player_destroy_cb_).Run();
+ }
+}
+
+void PipelineImpl::RendererWrapper::PlayerDestroyed() {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") ;"
+ << "signal: player is destroyed";
+ // signal
+ std::move(player_destroy_cb_).Run();
+}
#endif
void PipelineImpl::RendererWrapper::CreateRendererInternal(
base::BindPostTaskToCurrentDefault(std::move(cdm_attached_cb))));
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void PipelineImpl::DestroyPlayerSync(base::OnceClosure cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RendererWrapper::DestroyPlayerSync,
+ base::Unretained(renderer_wrapper_.get()), std::move(cb)));
+}
+#endif
+
#if defined(TIZEN_MULTIMEDIA)
void PipelineImpl::ToggleFullscreenMode(bool is_fullscreen,
ToggledFullscreenCB cb) {
void SetActiveAudioTrack(int index) override;
void SetActiveVideoTrack(int index) override;
void SetPreferTextLanguage(const std::string& lang) override;
+ void DestroyPlayerSync(base::OnceClosure cb) override;
#endif
void OnBufferingStateChange(BufferingState state,
BufferingStateChangeReason reason);
virtual void SetActiveAudioTrack(int index) {}
virtual void SetActiveVideoTrack(int index) {}
virtual void SetPreferTextLanguage(const std::string& lang) {}
+ virtual void DestroyPlayerSync(base::OnceClosure cb) {}
#endif
// Starts rendering from |time|.
}
pipeline_->SetPreferTextLanguage(lang);
}
+
+void PipelineController::DestroyPlayerSync(base::OnceClosure cb) {
+ if (pipeline_) {
+ pipeline_->DestroyPlayerSync(std::move(cb));
+ } else {
+ LOG(ERROR) << "pipeline_ is null";
+ std::move(cb).Run();
+ }
+}
#endif
} // namespace media
void SetActiveAudioTrack(int index);
void SetActiveVideoTrack(int index);
void SetPreferTextLanguage(const std::string& lang);
+ void DestroyPlayerSync(base::OnceClosure cb);
#endif
private:
// Attempts to make progress from the current state to the target state.
}
remote_renderer_->SetPreferTextLanguage(lang);
}
+
+void MojoRenderer::DestroyPlayerSync(base::OnceClosure cb) {
+ DVLOG(2) << __func__;
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(remote_renderer_.is_bound());
+ DCHECK(cb);
+ DCHECK(!player_destroy_cb_);
+
+ player_destroy_cb_ = std::move(cb);
+ remote_renderer_->DestroyPlayerSync(
+ base::BindOnce(&MojoRenderer::OnPlayerDestroyed, base::Unretained(this)));
+}
+
+void MojoRenderer::OnPlayerDestroyed() {
+ LOG(INFO) << "OnPlayerDestroyed";
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(player_destroy_cb_);
+
+ std::move(player_destroy_cb_).Run();
+}
#endif
void MojoRenderer::OnWaiting(WaitingReason reason) {
void SetActiveAudioTrack(int index) override;
void SetActiveVideoTrack(int index) override;
void SetPreferTextLanguage(const std::string& lang) override;
+ void DestroyPlayerSync(base::OnceClosure cb) override;
#endif
private:
void OnSeekCompleted();
#endif
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnPlayerDestroyed();
+#endif
+
void CancelPendingCallbacks();
// |task_runner| on which all methods are invoked, except for GetMediaTime(),
base::OnceClosure seek_cb_;
#endif
+#if BUILDFLAG(IS_TIZEN_TV)
+ base::OnceClosure player_destroy_cb_;
+#endif
+
float volume_ = 1.0f;
// Lock used to serialize access for |time_interpolator_|.
if (mojo_renderer_)
mojo_renderer_->SetPreferTextLanguage(lang);
}
+
+void MojoRendererWrapper::DestroyPlayerSync(base::OnceClosure cb) {
+ if (mojo_renderer_) {
+ mojo_renderer_->DestroyPlayerSync(std::move(cb));
+ } else {
+ LOG(ERROR) << "mojo_renderer_ is null";
+ std::move(cb).Run();
+ }
+}
#endif
} // namespace media
void SetActiveVideoTrack(int index) override;
void SetActiveAudioTrack(int index) override;
void SetPreferTextLanguage(const std::string& lang) override;
+ void DestroyPlayerSync(base::OnceClosure cb) override;
#endif
base::TimeDelta GetMediaTime() override;
[EnableIf=is_tizen_tv]
SetPreferTextLanguage(string lang);
+
+ [EnableIf=is_tizen_tv]
+ DestroyPlayerSync() => ();
};
// A Mojo equivalent of media::RendererClient. See media/mojo/README.md
}
renderer_->SetPreferTextLanguage(lang);
}
+
+void MojoRendererService::OnPlayerDestroyed(base::OnceClosure destroy_cb) {
+ LOG(INFO) << "OnPlayerDestroyed";
+ std::move(destroy_cb).Run();
+}
+
+void MojoRendererService::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+ DVLOG(2) << __func__;
+
+ if (renderer_) {
+ renderer_->DestroyPlayerSync(
+ base::BindOnce(&MojoRendererService::OnPlayerDestroyed, weak_this_,
+ std::move(destroy_cb)));
+ } else {
+ LOG(ERROR) << "renderer_ is null";
+ std::move(destroy_cb).Run();
+ }
+}
#endif
void MojoRendererService::OnBufferingStateChange(
void SetActiveAudioTrack(int index) final;
void SetActiveVideoTrack(int index) final;
void SetPreferTextLanguage(const std::string& lang) final;
+ void DestroyPlayerSync(base::OnceClosure destroy_cb) final;
#endif
private:
void OnFallback(PipelineStatus status) final;
void OnEnded() final;
void OnStatisticsUpdate(const PipelineStatistics& stats) final;
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnPlayerDestroyed(base::OnceClosure destroy_cb);
+#endif
void OnBufferingStateChange(BufferingState state,
BufferingStateChangeReason reason) final;
void OnWaiting(WaitingReason reason) final;
#include "build/build_config.h"
#include "cc/layers/video_layer.h"
#include "components/viz/common/gpu/raster_context_provider.h"
+#include "content/public/common/content_switches.h"
#include "media/audio/null_audio_sink.h"
#include "media/base/audio_renderer_sink.h"
#include "media/base/cdm_context.h"
std::move(media_thread_mem_dumper_));
main_thread_mem_dumper_.reset();
+#if BUILDFLAG(IS_TIZEN_TV)
+ // for app eme case, we must ensure player is destroyed before IEMEDrmBridge
+ // PipelineController::Stop will destroy player by mojom IPC and destroy
+ // finish time is not fixed Now we split the original PipelineController::Stop
+ // fuction to 2 parts:
+ // 1. DestroyPlayerSync only destroy MediaPlayerESPlusPlayer
+ // 2. Stop is the same with the original logic except 1, such as destroy
+ // MediaPlayerRendererClient/MojoRendererWrapper/MojoRenderer/MojoRendererService
+ // /TizenRendererImpl
+ if (IsSyncDestroyPlayerNeeded()) {
+ LOG(INFO) << "need destroy player sync...";
+ base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ pipeline_controller_->DestroyPlayerSync(base::BindOnce(
+ &base::WaitableEvent::Signal, base::Unretained(&waiter)));
+ waiter.Wait();
+ }
+#endif
+
// The underlying Pipeline must be stopped before it is destroyed.
//
// Note: This destruction happens synchronously on the media thread and
void WebMediaPlayerImpl::SetPreferTextLanguage(const std::string& lang) {
pipeline_controller_->SetPreferTextLanguage(lang);
}
+
+bool WebMediaPlayerImpl::IsSyncDestroyPlayerNeeded() {
+ bool single_process_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess);
+ bool isMSE = load_type_ == kLoadTypeMediaSource;
+ if (isMSE && single_process_mode && cdm_context_ref_)
+ return true;
+ return false;
+}
#endif
bool WebMediaPlayerImpl::CanPlayThrough() {
// Can return a nullptr.
scoped_refptr<media::VideoFrame> GetCurrentFrameFromCompositor() const;
+#if BUILDFLAG(IS_TIZEN_TV)
+ bool IsSyncDestroyPlayerNeeded();
+#endif
+
// Sets CdmContext from |cdm| on the pipeline and calls OnCdmAttached()
// when done.
void SetCdmInternal(WebContentDecryptionModule* cdm);
LOG_ID(ERROR, player_id_) << "media_player_ is null";
}
+void TizenRendererImpl::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+ if (media_player_) {
+ media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
+ player_id_, !resource_conflicted_);
+ media_player_->DestroyPlayerSync(std::move(destroy_cb));
+ } else {
+ LOG_ID(INFO, player_id_) << "media_player_ is nullptr";
+ std::move(destroy_cb).Run();
+ }
+}
+
bool TizenRendererImpl::PlaybackNotificationEnabled() {
content::WebContents* web_contents = GetWebContents();
if (!web_contents) {
#if BUILDFLAG(IS_TIZEN_TV)
void SetContentMimeType(const std::string& mime_type) override;
void SetParentalRatingResult(bool is_pass) override;
+ void DestroyPlayerSync(base::OnceClosure destroy_cb) override;
#endif
private:
}
MediaPlayerESPlusPlayer::~MediaPlayerESPlusPlayer() {
- LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+#if BUILDFLAG(IS_TIZEN_TV)
+ if (!esplayer_) {
+ LOG_ID(INFO, player_id_) << "player is already destroyed:" << (void*)this;
+ return;
+ }
+#endif
+
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << __func__;
weak_factory_.InvalidateWeakPtrs();
// Player should be released before destroyed.
esplayer_ = nullptr;
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void MediaPlayerESPlusPlayer::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+ if (!esplayer_) {
+ LOG_ID(INFO, player_id_) << "player is already destroyed:" << (void*)this;
+ std::move(destroy_cb).Run();
+ return;
+ }
+
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << __func__;
+ weak_factory_.InvalidateWeakPtrs();
+
+ Release();
+
+ int error = esplusplayer_destroy(esplayer_);
+ if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
+ LOG_ID(ERROR, player_id_)
+ << "esplusplayer_destroy failed, error #"
+ << esplusplayer_get_error_string(
+ static_cast<esplusplayer_error_type>(error));
+ esplayer_ = nullptr;
+
+ std::move(destroy_cb).Run();
+}
+#endif
+
bool MediaPlayerESPlusPlayer::CreatePlayer(int player_id) {
player_id_ = player_id;
}
void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
- LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << __func__;
if (!esplayer_) {
- LOG(INFO) << "(" << static_cast<void*>(this) << ") "
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
<< "esplayer is null.";
return;
}
void MediaPlayerESPlusPlayer::Prepare() {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
- if (!esplayer_ || is_prepared_ || is_preparing_)
+ if (!esplayer_ || is_prepared_ || is_preparing_) {
+ LOG_ID(ERROR, player_id_)
+ << "(" << static_cast<void*>(this) << ") " << __func__
+ << ", esplayer_: " << static_cast<void*>(esplayer_)
+ << ", is_prepared_: " << is_prepared_
+ << ", is_preparing_: " << is_preparing_;
return;
+ }
if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
}
bool MediaPlayerESPlusPlayer::CanPrepare() {
- return !IsPrepared() && !is_preparing_;
+ return esplayer_ && !IsPrepared() && !is_preparing_;
}
void MediaPlayerESPlusPlayer::Release() {
<< " rect : " << rect.ToString();
if (!esplayer_ || !video_plane_controller_) {
- LOG(INFO)
+ LOG_ID(INFO, player_id_)
<< "(" << static_cast<void*>(this) << ") "
<< "player is destroyed, or video plane controller not exist.";
return;
}
void MediaPlayerESPlusPlayer::PrepareVideoHole() {
- LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
- if (!esplayer_ || is_prepared_ || is_preparing_)
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << __func__;
+ if (!esplayer_ || is_prepared_ || is_preparing_) {
+ LOG_ID(ERROR, player_id_)
+ << "(" << static_cast<void*>(this) << ") " << __func__
+ << ", esplayer_: " << static_cast<void*>(esplayer_)
+ << ", is_prepared_: " << is_prepared_
+ << ", is_preparing_: " << is_preparing_;
return;
-
+ }
if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
<< " Prepare called on invalid state : "
void DestroyMediaPacket(void* media_packet) override;
#endif
+#if BUILDFLAG(IS_TIZEN_TV)
+ void DestroyPlayerSync(base::OnceClosure destroy_cb) override;
+#endif
+
// Callback handler
void OnReadyToPrepare(const esplusplayer_stream_type stream_type);
virtual void OnPrepareComplete(bool result);
void MediaPlayerESPlusPlayerTV::Initialize(VideoRendererSink* sink) {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+
+ if (!esplayer_) {
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << "esplayer is null.";
+ return;
+ }
+
single_process_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
MediaPlayerESPlusPlayer::Initialize(sink);
DemuxerStream::Type type) {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ if (!esplayer_) {
+ LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+ << "esplayer is null.";
+ return;
+ }
+
MediaPlayerESPlusPlayer::InitializeStreamConfig(type);
}
virtual void SetActiveVideoTrack(int index) {}
virtual void SetPreferTextLanguage(const std::string& lang) {}
virtual void UpdateEventData(std::string data) {}
+#if BUILDFLAG(IS_TIZEN_TV)
+ virtual void DestroyPlayerSync(base::OnceClosure destroy_cb) {}
+#endif
};
} // namespace media