1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/mojo_renderer_service.h"
10 #include "base/functional/bind.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/time/time.h"
13 #include "media/base/cdm_context.h"
14 #include "media/base/media_url_demuxer.h"
15 #include "media/base/renderer.h"
16 #include "media/mojo/common/media_type_converters.h"
17 #include "media/mojo/services/media_resource_shim.h"
18 #include "media/mojo/services/mojo_cdm_service_context.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
23 // Time interval to update media time.
24 constexpr auto kTimeUpdateInterval = base::Milliseconds(50);
27 mojo::SelfOwnedReceiverRef<mojom::Renderer> MojoRendererService::Create(
28 MojoCdmServiceContext* mojo_cdm_service_context,
29 std::unique_ptr<media::Renderer> renderer,
30 mojo::PendingReceiver<mojom::Renderer> receiver) {
31 MojoRendererService* service =
32 new MojoRendererService(mojo_cdm_service_context, std::move(renderer));
34 mojo::SelfOwnedReceiverRef<mojom::Renderer> self_owned_receiver =
35 mojo::MakeSelfOwnedReceiver<mojom::Renderer>(base::WrapUnique(service),
38 return self_owned_receiver;
41 MojoRendererService::MojoRendererService(
42 MojoCdmServiceContext* mojo_cdm_service_context,
43 std::unique_ptr<media::Renderer> renderer)
44 : mojo_cdm_service_context_(mojo_cdm_service_context),
45 state_(STATE_UNINITIALIZED),
47 renderer_(std::move(renderer)) {
51 weak_this_ = weak_factory_.GetWeakPtr();
54 MojoRendererService::~MojoRendererService() = default;
56 void MojoRendererService::Initialize(
57 mojo::PendingAssociatedRemote<mojom::RendererClient> client,
58 absl::optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>>
60 mojom::MediaUrlParamsPtr media_url_params,
61 InitializeCallback callback) {
63 DCHECK_EQ(state_, STATE_UNINITIALIZED);
65 client_.Bind(std::move(client));
66 state_ = STATE_INITIALIZING;
68 if (!media_url_params) {
69 DCHECK(streams.has_value());
70 media_resource_ = std::make_unique<MediaResourceShim>(
72 base::BindOnce(&MojoRendererService::OnAllStreamsReady, weak_this_,
73 std::move(callback)));
77 DCHECK(!media_url_params->media_url.is_empty());
78 media_resource_ = std::make_unique<MediaUrlDemuxer>(
79 nullptr, media_url_params->media_url, media_url_params->site_for_cookies,
80 media_url_params->top_frame_origin, media_url_params->has_storage_access,
81 media_url_params->allow_credentials, media_url_params->is_hls);
82 renderer_->Initialize(
83 media_resource_.get(), this,
84 base::BindOnce(&MojoRendererService::OnRendererInitializeDone, weak_this_,
85 std::move(callback)));
88 void MojoRendererService::Flush(FlushCallback callback) {
90 DCHECK(state_ == STATE_PLAYING || state_ == STATE_ERROR);
92 if (state_ == STATE_ERROR) {
93 std::move(callback).Run();
97 state_ = STATE_FLUSHING;
98 CancelPeriodicMediaTimeUpdates();
99 renderer_->Flush(base::BindOnce(&MojoRendererService::OnFlushCompleted,
100 weak_this_, std::move(callback)));
103 #if defined(TIZEN_MULTIMEDIA)
104 void MojoRendererService::Seek(base::TimeDelta time, SeekCallback seek_cb) {
105 DVLOG(2) << __func__ << ": " << time;
106 renderer_->Seek(time, base::BindOnce(&MojoRendererService::OnSeekCompleted,
107 weak_this_, std::move(seek_cb)));
110 void MojoRendererService::Suspend() {
111 DVLOG(2) << __func__;
112 renderer_->Suspend();
115 void MojoRendererService::ToggleFullscreenMode(
117 ToggleFullscreenModeCallback callback) {
118 DVLOG(2) << __func__ << " is_fullscreen: " << is_fullscreen;
119 renderer_->ToggleFullscreenMode(is_fullscreen, std::move(callback));
123 void MojoRendererService::StartPlayingFrom(base::TimeDelta time_delta) {
124 DVLOG(2) << __func__ << ": " << time_delta;
125 renderer_->StartPlayingFrom(time_delta);
126 SchedulePeriodicMediaTimeUpdates();
129 void MojoRendererService::SetPlaybackRate(double playback_rate) {
130 DVLOG(2) << __func__ << ": " << playback_rate;
131 DCHECK(state_ == STATE_PLAYING || state_ == STATE_ERROR);
132 playback_rate_ = playback_rate;
133 renderer_->SetPlaybackRate(playback_rate);
136 void MojoRendererService::SetVolume(float volume) {
137 renderer_->SetVolume(volume);
140 void MojoRendererService::SetCdm(
141 const absl::optional<base::UnguessableToken>& cdm_id,
142 SetCdmCallback callback) {
143 if (cdm_context_ref_) {
144 DVLOG(1) << "Switching CDM not supported";
145 std::move(callback).Run(false);
149 if (!mojo_cdm_service_context_) {
150 DVLOG(1) << "CDM service context not available.";
151 std::move(callback).Run(false);
156 DVLOG(1) << "The CDM ID is invalid.";
157 std::move(callback).Run(false);
161 auto cdm_context_ref =
162 mojo_cdm_service_context_->GetCdmContextRef(cdm_id.value());
163 if (!cdm_context_ref) {
164 DVLOG(1) << "CdmContextRef not found for CDM ID: " << cdm_id.value();
165 std::move(callback).Run(false);
169 // |cdm_context_ref_| must be kept as long as |cdm_context| is used by the
171 cdm_context_ref_ = std::move(cdm_context_ref);
172 auto* cdm_context = cdm_context_ref_->GetCdmContext();
175 renderer_->SetCdm(cdm_context,
176 base::BindOnce(&MojoRendererService::OnCdmAttached,
177 weak_this_, std::move(callback)));
180 #if defined(TIZEN_VIDEO_HOLE)
181 void MojoRendererService::SetVideoHole(bool is_video_hole) {
182 renderer_->SetVideoHole(is_video_hole);
185 void MojoRendererService::SetMediaGeometry(const gfx::RectF& rect) {
186 renderer_->SetMediaGeometry(rect);
190 void MojoRendererService::OnError(PipelineStatus error) {
191 DVLOG(1) << __func__ << "(" << error << ")";
192 state_ = STATE_ERROR;
193 CancelPeriodicMediaTimeUpdates();
194 client_->OnError(std::move(error));
197 void MojoRendererService::OnFallback(PipelineStatus error) {
201 void MojoRendererService::OnEnded() {
202 DVLOG(1) << __func__;
203 CancelPeriodicMediaTimeUpdates();
207 void MojoRendererService::OnStatisticsUpdate(const PipelineStatistics& stats) {
208 DVLOG(3) << __func__;
209 client_->OnStatisticsUpdate(stats);
212 #if BUILDFLAG(IS_TIZEN_TV)
213 void MojoRendererService::SetContentMimeType(const std::string& mime_type) {
214 DVLOG(3) << __func__ << ", mime_type: " << mime_type;
216 renderer_->SetContentMimeType(mime_type);
219 void MojoRendererService::SetParentalRatingResult(bool is_pass) {
220 DVLOG(3) << __func__;
222 renderer_->SetParentalRatingResult(is_pass);
224 LOG(ERROR) << "renderer_ is null";
228 void MojoRendererService::OnBufferingStateChange(
229 BufferingState state,
230 BufferingStateChangeReason reason) {
231 DVLOG(2) << __func__ << "(" << state << ", " << reason << ")";
232 client_->OnBufferingStateChange(state, reason);
235 void MojoRendererService::OnWaiting(WaitingReason reason) {
236 DVLOG(1) << __func__;
237 client_->OnWaiting(reason);
240 void MojoRendererService::OnAudioConfigChange(
241 const AudioDecoderConfig& config) {
242 DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
243 client_->OnAudioConfigChange(config);
246 void MojoRendererService::OnVideoConfigChange(
247 const VideoDecoderConfig& config) {
248 DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
249 client_->OnVideoConfigChange(config);
252 void MojoRendererService::OnVideoNaturalSizeChange(const gfx::Size& size) {
253 DVLOG(2) << __func__ << "(" << size.ToString() << ")";
254 client_->OnVideoNaturalSizeChange(size);
257 void MojoRendererService::OnVideoOpacityChange(bool opaque) {
258 DVLOG(2) << __func__ << "(" << opaque << ")";
259 client_->OnVideoOpacityChange(opaque);
262 #if defined(TIZEN_MULTIMEDIA)
263 void MojoRendererService::OnRequestSuspend(bool resource_conflicted) {
264 DVLOG(2) << __func__;
265 client_->OnRequestSuspend(resource_conflicted);
268 void MojoRendererService::OnRequestSeek(base::TimeDelta time) {
269 DVLOG(2) << __func__ << "(" << time << ")";
270 client_->OnRequestSeek(time);
273 void MojoRendererService::OnSeekableTimeChange(base::TimeDelta min_time,
274 base::TimeDelta max_time,
276 DVLOG(2) << __func__ << " min_time " << min_time << " max_time " << max_time
277 << "is_live " << is_live;
278 client_->OnSeekableTimeChange(min_time, max_time, is_live);
281 void MojoRendererService::OnLivePlaybackComplete() {
282 DVLOG(2) << __func__;
283 client_->OnLivePlaybackComplete();
287 void MojoRendererService::OnVideoFrameRateChange(absl::optional<int> fps) {
288 DVLOG(2) << __func__ << "(" << (fps ? *fps : -1) << ")";
289 // TODO(liberato): plumb to |client_|.
292 void MojoRendererService::OnAllStreamsReady(
293 base::OnceCallback<void(bool)> callback) {
294 DCHECK_EQ(state_, STATE_INITIALIZING);
296 renderer_->Initialize(
297 media_resource_.get(), this,
298 base::BindOnce(&MojoRendererService::OnRendererInitializeDone, weak_this_,
299 std::move(callback)));
302 void MojoRendererService::OnRendererInitializeDone(
303 base::OnceCallback<void(bool)> callback,
304 PipelineStatus status) {
305 DVLOG(1) << __func__;
306 DCHECK_EQ(state_, STATE_INITIALIZING);
308 if (status != PIPELINE_OK) {
309 state_ = STATE_ERROR;
310 std::move(callback).Run(false);
314 state_ = STATE_PLAYING;
315 std::move(callback).Run(true);
318 void MojoRendererService::UpdateMediaTime(bool force) {
319 const base::TimeDelta media_time = renderer_->GetMediaTime();
320 if (!force && media_time == last_media_time_)
323 base::TimeDelta max_time = media_time;
324 // Allow some slop to account for delays in scheduling time update tasks.
325 if (time_update_timer_.IsRunning() && (playback_rate_ > 0))
326 max_time += 2 * kTimeUpdateInterval;
328 client_->OnTimeUpdate(media_time, max_time, base::TimeTicks::Now());
329 last_media_time_ = media_time;
332 void MojoRendererService::CancelPeriodicMediaTimeUpdates() {
333 DVLOG(2) << __func__;
335 time_update_timer_.Stop();
336 UpdateMediaTime(/*force=*/false);
339 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() {
340 DVLOG(2) << __func__;
342 UpdateMediaTime(/*force=*/true);
343 time_update_timer_.Start(
344 FROM_HERE, kTimeUpdateInterval,
345 base::BindRepeating(&MojoRendererService::UpdateMediaTime, weak_this_,
349 void MojoRendererService::OnFlushCompleted(FlushCallback callback) {
350 DVLOG(1) << __func__;
351 DCHECK(state_ == STATE_FLUSHING || state_ == STATE_ERROR);
353 if (state_ == STATE_FLUSHING)
354 state_ = STATE_PLAYING;
356 std::move(callback).Run();
359 void MojoRendererService::OnCdmAttached(base::OnceCallback<void(bool)> callback,
361 DVLOG(1) << __func__ << "(" << success << ")";
364 cdm_context_ref_.reset();
366 std::move(callback).Run(success);
369 #if defined(TIZEN_MULTIMEDIA)
370 void MojoRendererService::OnSeekCompleted(SeekCallback seek_cb) {
371 DVLOG(1) << __func__;
372 std::move(seek_cb).Run();