[M120 Migration][MM] Handle live stream duration and currenttime
[platform/framework/web/chromium-efl.git] / media / mojo / services / mojo_renderer_service.cc
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.
4
5 #include "media/mojo/services/mojo_renderer_service.h"
6
7 #include <memory>
8 #include <utility>
9
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"
20
21 namespace media {
22
23 // Time interval to update media time.
24 constexpr auto kTimeUpdateInterval = base::Milliseconds(50);
25
26 // static
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));
33
34   mojo::SelfOwnedReceiverRef<mojom::Renderer> self_owned_receiver =
35       mojo::MakeSelfOwnedReceiver<mojom::Renderer>(base::WrapUnique(service),
36                                                    std::move(receiver));
37
38   return self_owned_receiver;
39 }
40
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),
46       playback_rate_(0),
47       renderer_(std::move(renderer)) {
48   DVLOG(1) << __func__;
49   DCHECK(renderer_);
50
51   weak_this_ = weak_factory_.GetWeakPtr();
52 }
53
54 MojoRendererService::~MojoRendererService() = default;
55
56 void MojoRendererService::Initialize(
57     mojo::PendingAssociatedRemote<mojom::RendererClient> client,
58     absl::optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>>
59         streams,
60     mojom::MediaUrlParamsPtr media_url_params,
61     InitializeCallback callback) {
62   DVLOG(1) << __func__;
63   DCHECK_EQ(state_, STATE_UNINITIALIZED);
64
65   client_.Bind(std::move(client));
66   state_ = STATE_INITIALIZING;
67
68   if (!media_url_params) {
69     DCHECK(streams.has_value());
70     media_resource_ = std::make_unique<MediaResourceShim>(
71         std::move(*streams),
72         base::BindOnce(&MojoRendererService::OnAllStreamsReady, weak_this_,
73                        std::move(callback)));
74     return;
75   }
76
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)));
86 }
87
88 void MojoRendererService::Flush(FlushCallback callback) {
89   DVLOG(2) << __func__;
90   DCHECK(state_ == STATE_PLAYING || state_ == STATE_ERROR);
91
92   if (state_ == STATE_ERROR) {
93     std::move(callback).Run();
94     return;
95   }
96
97   state_ = STATE_FLUSHING;
98   CancelPeriodicMediaTimeUpdates();
99   renderer_->Flush(base::BindOnce(&MojoRendererService::OnFlushCompleted,
100                                   weak_this_, std::move(callback)));
101 }
102
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)));
108 }
109
110 void MojoRendererService::Suspend() {
111   DVLOG(2) << __func__;
112   renderer_->Suspend();
113 }
114
115 void MojoRendererService::ToggleFullscreenMode(
116     bool is_fullscreen,
117     ToggleFullscreenModeCallback callback) {
118   DVLOG(2) << __func__ << " is_fullscreen: " << is_fullscreen;
119   renderer_->ToggleFullscreenMode(is_fullscreen, std::move(callback));
120 }
121 #endif
122
123 void MojoRendererService::StartPlayingFrom(base::TimeDelta time_delta) {
124   DVLOG(2) << __func__ << ": " << time_delta;
125   renderer_->StartPlayingFrom(time_delta);
126   SchedulePeriodicMediaTimeUpdates();
127 }
128
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);
134 }
135
136 void MojoRendererService::SetVolume(float volume) {
137   renderer_->SetVolume(volume);
138 }
139
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);
146     return;
147   }
148
149   if (!mojo_cdm_service_context_) {
150     DVLOG(1) << "CDM service context not available.";
151     std::move(callback).Run(false);
152     return;
153   }
154
155   if (!cdm_id) {
156     DVLOG(1) << "The CDM ID is invalid.";
157     std::move(callback).Run(false);
158     return;
159   }
160
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);
166     return;
167   }
168
169   // |cdm_context_ref_| must be kept as long as |cdm_context| is used by the
170   // |renderer_|.
171   cdm_context_ref_ = std::move(cdm_context_ref);
172   auto* cdm_context = cdm_context_ref_->GetCdmContext();
173   DCHECK(cdm_context);
174
175   renderer_->SetCdm(cdm_context,
176                     base::BindOnce(&MojoRendererService::OnCdmAttached,
177                                    weak_this_, std::move(callback)));
178 }
179
180 #if defined(TIZEN_VIDEO_HOLE)
181 void MojoRendererService::SetVideoHole(bool is_video_hole) {
182   renderer_->SetVideoHole(is_video_hole);
183 }
184
185 void MojoRendererService::SetMediaGeometry(const gfx::RectF& rect) {
186   renderer_->SetMediaGeometry(rect);
187 }
188 #endif
189
190 void MojoRendererService::OnError(PipelineStatus error) {
191   DVLOG(1) << __func__ << "(" << error << ")";
192   state_ = STATE_ERROR;
193   CancelPeriodicMediaTimeUpdates();
194   client_->OnError(std::move(error));
195 }
196
197 void MojoRendererService::OnFallback(PipelineStatus error) {
198   NOTREACHED();
199 }
200
201 void MojoRendererService::OnEnded() {
202   DVLOG(1) << __func__;
203   CancelPeriodicMediaTimeUpdates();
204   client_->OnEnded();
205 }
206
207 void MojoRendererService::OnStatisticsUpdate(const PipelineStatistics& stats) {
208   DVLOG(3) << __func__;
209   client_->OnStatisticsUpdate(stats);
210 }
211
212 #if BUILDFLAG(IS_TIZEN_TV)
213 void MojoRendererService::SetContentMimeType(const std::string& mime_type) {
214   DVLOG(3) << __func__ << ", mime_type: " << mime_type;
215   if (renderer_)
216     renderer_->SetContentMimeType(mime_type);
217 }
218
219 void MojoRendererService::SetParentalRatingResult(bool is_pass) {
220   DVLOG(3) << __func__;
221   if (renderer_)
222     renderer_->SetParentalRatingResult(is_pass);
223   else
224     LOG(ERROR) << "renderer_ is null";
225 }
226 #endif
227
228 void MojoRendererService::OnBufferingStateChange(
229     BufferingState state,
230     BufferingStateChangeReason reason) {
231   DVLOG(2) << __func__ << "(" << state << ", " << reason << ")";
232   client_->OnBufferingStateChange(state, reason);
233 }
234
235 void MojoRendererService::OnWaiting(WaitingReason reason) {
236   DVLOG(1) << __func__;
237   client_->OnWaiting(reason);
238 }
239
240 void MojoRendererService::OnAudioConfigChange(
241     const AudioDecoderConfig& config) {
242   DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
243   client_->OnAudioConfigChange(config);
244 }
245
246 void MojoRendererService::OnVideoConfigChange(
247     const VideoDecoderConfig& config) {
248   DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
249   client_->OnVideoConfigChange(config);
250 }
251
252 void MojoRendererService::OnVideoNaturalSizeChange(const gfx::Size& size) {
253   DVLOG(2) << __func__ << "(" << size.ToString() << ")";
254   client_->OnVideoNaturalSizeChange(size);
255 }
256
257 void MojoRendererService::OnVideoOpacityChange(bool opaque) {
258   DVLOG(2) << __func__ << "(" << opaque << ")";
259   client_->OnVideoOpacityChange(opaque);
260 }
261
262 #if defined(TIZEN_MULTIMEDIA)
263 void MojoRendererService::OnRequestSuspend(bool resource_conflicted) {
264   DVLOG(2) << __func__;
265   client_->OnRequestSuspend(resource_conflicted);
266 }
267
268 void MojoRendererService::OnRequestSeek(base::TimeDelta time) {
269   DVLOG(2) << __func__ << "(" << time << ")";
270   client_->OnRequestSeek(time);
271 }
272
273 void MojoRendererService::OnSeekableTimeChange(base::TimeDelta min_time,
274                                                base::TimeDelta max_time,
275                                                bool is_live) {
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);
279 }
280
281 void MojoRendererService::OnLivePlaybackComplete() {
282   DVLOG(2) << __func__;
283   client_->OnLivePlaybackComplete();
284 }
285 #endif
286
287 void MojoRendererService::OnVideoFrameRateChange(absl::optional<int> fps) {
288   DVLOG(2) << __func__ << "(" << (fps ? *fps : -1) << ")";
289   // TODO(liberato): plumb to |client_|.
290 }
291
292 void MojoRendererService::OnAllStreamsReady(
293     base::OnceCallback<void(bool)> callback) {
294   DCHECK_EQ(state_, STATE_INITIALIZING);
295
296   renderer_->Initialize(
297       media_resource_.get(), this,
298       base::BindOnce(&MojoRendererService::OnRendererInitializeDone, weak_this_,
299                      std::move(callback)));
300 }
301
302 void MojoRendererService::OnRendererInitializeDone(
303     base::OnceCallback<void(bool)> callback,
304     PipelineStatus status) {
305   DVLOG(1) << __func__;
306   DCHECK_EQ(state_, STATE_INITIALIZING);
307
308   if (status != PIPELINE_OK) {
309     state_ = STATE_ERROR;
310     std::move(callback).Run(false);
311     return;
312   }
313
314   state_ = STATE_PLAYING;
315   std::move(callback).Run(true);
316 }
317
318 void MojoRendererService::UpdateMediaTime(bool force) {
319   const base::TimeDelta media_time = renderer_->GetMediaTime();
320   if (!force && media_time == last_media_time_)
321     return;
322
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;
327
328   client_->OnTimeUpdate(media_time, max_time, base::TimeTicks::Now());
329   last_media_time_ = media_time;
330 }
331
332 void MojoRendererService::CancelPeriodicMediaTimeUpdates() {
333   DVLOG(2) << __func__;
334
335   time_update_timer_.Stop();
336   UpdateMediaTime(/*force=*/false);
337 }
338
339 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() {
340   DVLOG(2) << __func__;
341
342   UpdateMediaTime(/*force=*/true);
343   time_update_timer_.Start(
344       FROM_HERE, kTimeUpdateInterval,
345       base::BindRepeating(&MojoRendererService::UpdateMediaTime, weak_this_,
346                           /*force=*/false));
347 }
348
349 void MojoRendererService::OnFlushCompleted(FlushCallback callback) {
350   DVLOG(1) << __func__;
351   DCHECK(state_ == STATE_FLUSHING || state_ == STATE_ERROR);
352
353   if (state_ == STATE_FLUSHING)
354     state_ = STATE_PLAYING;
355
356   std::move(callback).Run();
357 }
358
359 void MojoRendererService::OnCdmAttached(base::OnceCallback<void(bool)> callback,
360                                         bool success) {
361   DVLOG(1) << __func__ << "(" << success << ")";
362
363   if (!success)
364     cdm_context_ref_.reset();
365
366   std::move(callback).Run(success);
367 }
368
369 #if defined(TIZEN_MULTIMEDIA)
370 void MojoRendererService::OnSeekCompleted(SeekCallback seek_cb) {
371   DVLOG(1) << __func__;
372   std::move(seek_cb).Run();
373 }
374 #endif
375
376 }  // namespace media