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/renderers/renderer_impl.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/location.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/task/bind_post_task.h"
19 #include "base/task/sequenced_task_runner.h"
20 #include "base/task/single_thread_task_runner.h"
21 #include "base/trace_event/trace_event.h"
22 #include "media/base/audio_decoder_config.h"
23 #include "media/base/audio_renderer.h"
24 #include "media/base/media_log.h"
25 #include "media/base/media_resource.h"
26 #include "media/base/media_switches.h"
27 #include "media/base/renderer_client.h"
28 #include "media/base/time_source.h"
29 #include "media/base/video_decoder_config.h"
30 #include "media/base/video_renderer.h"
31 #include "media/base/wall_clock_time_source.h"
35 class RendererImpl::RendererClientInternal final : public RendererClient {
37 RendererClientInternal(DemuxerStream::Type type,
38 RendererImpl* renderer,
39 MediaResource* media_resource)
40 : type_(type), renderer_(renderer), media_resource_(media_resource) {
41 DCHECK((type_ == DemuxerStream::AUDIO) || (type_ == DemuxerStream::VIDEO));
44 void OnError(PipelineStatus error) override { renderer_->OnError(error); }
45 void OnFallback(PipelineStatus error) override {
46 renderer_->OnFallback(std::move(error).AddHere());
48 void OnEnded() override { renderer_->OnRendererEnded(type_); }
49 void OnStatisticsUpdate(const PipelineStatistics& stats) override {
50 renderer_->OnStatisticsUpdate(stats);
52 void OnBufferingStateChange(BufferingState state,
53 BufferingStateChangeReason reason) override {
54 renderer_->OnBufferingStateChange(type_, state, reason);
56 void OnWaiting(WaitingReason reason) override {
57 renderer_->OnWaiting(reason);
59 void OnAudioConfigChange(const AudioDecoderConfig& config) override {
60 renderer_->OnAudioConfigChange(config);
62 void OnVideoConfigChange(const VideoDecoderConfig& config) override {
63 renderer_->OnVideoConfigChange(config);
65 void OnVideoNaturalSizeChange(const gfx::Size& size) override {
66 DCHECK(type_ == DemuxerStream::VIDEO);
67 renderer_->OnVideoNaturalSizeChange(size);
69 void OnVideoOpacityChange(bool opaque) override {
70 DCHECK(type_ == DemuxerStream::VIDEO);
71 renderer_->OnVideoOpacityChange(opaque);
73 void OnVideoFrameRateChange(absl::optional<int> fps) override {
74 DCHECK(type_ == DemuxerStream::VIDEO);
75 renderer_->OnVideoFrameRateChange(fps);
78 bool IsVideoStreamAvailable() override {
79 return media_resource_->GetFirstStream(::media::DemuxerStream::VIDEO);
83 DemuxerStream::Type type_;
84 raw_ptr<RendererImpl> renderer_;
85 raw_ptr<MediaResource> media_resource_;
88 RendererImpl::RendererImpl(
89 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
90 std::unique_ptr<AudioRenderer> audio_renderer,
91 std::unique_ptr<VideoRenderer> video_renderer)
92 : state_(STATE_UNINITIALIZED),
93 task_runner_(task_runner),
94 audio_renderer_(std::move(audio_renderer)),
95 video_renderer_(std::move(video_renderer)),
96 current_audio_stream_(nullptr),
97 current_video_stream_(nullptr),
98 time_source_(nullptr),
101 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
102 video_buffering_state_(BUFFERING_HAVE_NOTHING),
105 audio_playing_(false),
106 video_playing_(false),
107 cdm_context_(nullptr),
108 underflow_disabled_for_testing_(false),
109 clockless_video_playback_enabled_for_testing_(false),
110 pending_audio_track_change_(false),
111 pending_video_track_change_(false) {
112 weak_this_ = weak_factory_.GetWeakPtr();
113 DVLOG(1) << __func__;
116 RendererImpl::~RendererImpl() {
117 DVLOG(1) << __func__;
118 DCHECK(task_runner_->RunsTasksInCurrentSequence());
120 // RendererImpl is being destroyed, so invalidate weak pointers right away to
121 // avoid getting callbacks which might try to access fields that has been
122 // destroyed, e.g. audio_renderer_/video_renderer_ below (crbug.com/668963).
123 weak_factory_.InvalidateWeakPtrs();
125 // Tear down in opposite order of construction as |video_renderer_| can still
126 // need |time_source_| (which can be |audio_renderer_|) to be alive.
127 video_renderer_.reset();
128 audio_renderer_.reset();
131 FinishInitialization(PIPELINE_ERROR_ABORT);
136 void RendererImpl::Initialize(MediaResource* media_resource,
137 RendererClient* client,
138 PipelineStatusCallback init_cb) {
139 DVLOG(1) << __func__;
140 DCHECK(task_runner_->RunsTasksInCurrentSequence());
141 DCHECK_EQ(state_, STATE_UNINITIALIZED);
144 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("media", "RendererImpl::Initialize",
145 TRACE_ID_LOCAL(this));
148 media_resource_ = media_resource;
149 init_cb_ = std::move(init_cb);
151 if (HasEncryptedStream() && !cdm_context_) {
152 DVLOG(1) << __func__ << ": Has encrypted stream but CDM is not set.";
153 state_ = STATE_INIT_PENDING_CDM;
154 OnWaiting(WaitingReason::kNoCdm);
158 state_ = STATE_INITIALIZING;
159 InitializeAudioRenderer();
162 void RendererImpl::SetCdm(CdmContext* cdm_context,
163 CdmAttachedCB cdm_attached_cb) {
164 DVLOG(1) << __func__;
165 DCHECK(task_runner_->RunsTasksInCurrentSequence());
167 TRACE_EVENT0("media", "RendererImpl::SetCdm");
170 DVLOG(1) << "Switching CDM not supported.";
171 std::move(cdm_attached_cb).Run(false);
175 cdm_context_ = cdm_context;
176 std::move(cdm_attached_cb).Run(true);
178 if (state_ != STATE_INIT_PENDING_CDM)
182 state_ = STATE_INITIALIZING;
183 InitializeAudioRenderer();
186 void RendererImpl::SetLatencyHint(
187 absl::optional<base::TimeDelta> latency_hint) {
188 DVLOG(1) << __func__;
189 DCHECK(!latency_hint || (*latency_hint >= base::TimeDelta()));
190 DCHECK(task_runner_->RunsTasksInCurrentSequence());
193 video_renderer_->SetLatencyHint(latency_hint);
196 audio_renderer_->SetLatencyHint(latency_hint);
199 void RendererImpl::SetPreservesPitch(bool preserves_pitch) {
200 DVLOG(1) << __func__;
201 DCHECK(task_runner_->RunsTasksInCurrentSequence());
204 audio_renderer_->SetPreservesPitch(preserves_pitch);
207 void RendererImpl::SetWasPlayedWithUserActivation(
208 bool was_played_with_user_activation) {
209 DVLOG(1) << __func__;
210 DCHECK(task_runner_->RunsTasksInCurrentSequence());
213 audio_renderer_->SetWasPlayedWithUserActivation(
214 was_played_with_user_activation);
217 void RendererImpl::Flush(base::OnceClosure flush_cb) {
218 DVLOG(1) << __func__;
219 DCHECK(task_runner_->RunsTasksInCurrentSequence());
221 DCHECK(!(pending_audio_track_change_ || pending_video_track_change_));
222 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("media", "RendererImpl::Flush",
223 TRACE_ID_LOCAL(this));
225 if (state_ == STATE_FLUSHED) {
226 flush_cb_ = base::BindPostTaskToCurrentDefault(std::move(flush_cb));
231 if (state_ != STATE_PLAYING) {
232 DCHECK_EQ(state_, STATE_ERROR);
236 flush_cb_ = std::move(flush_cb);
237 state_ = STATE_FLUSHING;
239 // If a stream restart is pending, this Flush() will complete it. Upon flush
240 // completion any pending actions will be executed as well.
244 void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
245 DVLOG(1) << __func__;
246 DCHECK(task_runner_->RunsTasksInCurrentSequence());
247 TRACE_EVENT1("media", "RendererImpl::StartPlayingFrom", "time_us",
248 time.InMicroseconds());
250 if (state_ != STATE_FLUSHED) {
251 DCHECK_EQ(state_, STATE_ERROR);
255 time_source_->SetMediaTime(time);
257 state_ = STATE_PLAYING;
258 if (audio_renderer_) {
259 audio_playing_ = true;
260 audio_renderer_->StartPlaying();
262 if (video_renderer_) {
263 video_playing_ = true;
264 video_renderer_->StartPlayingFrom(time);
268 void RendererImpl::SetPlaybackRate(double playback_rate) {
269 DVLOG(1) << __func__ << "(" << playback_rate << ")";
270 DCHECK(task_runner_->RunsTasksInCurrentSequence());
271 TRACE_EVENT1("media", "RendererImpl::SetPlaybackRate", "rate", playback_rate);
273 // Playback rate changes are only carried out while playing.
274 if (state_ != STATE_PLAYING && state_ != STATE_FLUSHED)
277 time_source_->SetPlaybackRate(playback_rate);
279 const double old_rate = playback_rate_;
280 playback_rate_ = playback_rate;
281 if (!time_ticking_ || !video_renderer_)
284 if (old_rate == 0 && playback_rate > 0)
285 video_renderer_->OnTimeProgressing();
286 else if (old_rate > 0 && playback_rate == 0)
287 video_renderer_->OnTimeStopped();
290 void RendererImpl::SetVolume(float volume) {
291 DVLOG(1) << __func__;
292 DCHECK(task_runner_->RunsTasksInCurrentSequence());
295 audio_renderer_->SetVolume(volume);
298 base::TimeDelta RendererImpl::GetMediaTime() {
299 // No BelongsToCurrentThread() checking because this can be called from other
302 base::AutoLock lock(restarting_audio_lock_);
303 if (pending_audio_track_change_) {
304 DCHECK_NE(kNoTimestamp, restarting_audio_time_);
305 return restarting_audio_time_;
309 return time_source_->CurrentMediaTime();
312 void RendererImpl::DisableUnderflowForTesting() {
313 DVLOG(1) << __func__;
314 DCHECK(task_runner_->RunsTasksInCurrentSequence());
315 DCHECK_EQ(state_, STATE_UNINITIALIZED);
317 underflow_disabled_for_testing_ = true;
320 void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
321 DVLOG(1) << __func__;
322 DCHECK(task_runner_->RunsTasksInCurrentSequence());
323 DCHECK_EQ(state_, STATE_UNINITIALIZED);
324 DCHECK(underflow_disabled_for_testing_)
325 << "Underflow must be disabled for clockless video playback";
327 clockless_video_playback_enabled_for_testing_ = true;
330 bool RendererImpl::GetWallClockTimes(
331 const std::vector<base::TimeDelta>& media_timestamps,
332 std::vector<base::TimeTicks>* wall_clock_times) {
333 // No BelongsToCurrentThread() checking because this can be called from other
336 // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
337 // which should go away at some point http://crbug.com/110814
338 if (clockless_video_playback_enabled_for_testing_) {
339 if (media_timestamps.empty()) {
340 *wall_clock_times = std::vector<base::TimeTicks>(1,
341 base::TimeTicks::Now());
343 *wall_clock_times = std::vector<base::TimeTicks>();
344 for (auto const &media_time : media_timestamps) {
345 wall_clock_times->push_back(base::TimeTicks() + media_time);
351 return time_source_->GetWallClockTimes(media_timestamps, wall_clock_times);
354 bool RendererImpl::HasEncryptedStream() {
355 std::vector<DemuxerStream*> demuxer_streams =
356 media_resource_->GetAllStreams();
358 for (auto* stream : demuxer_streams) {
359 if (stream->type() == DemuxerStream::AUDIO &&
360 stream->audio_decoder_config().is_encrypted())
362 if (stream->type() == DemuxerStream::VIDEO &&
363 stream->video_decoder_config().is_encrypted())
370 void RendererImpl::FinishInitialization(PipelineStatus status) {
372 TRACE_EVENT_NESTABLE_ASYNC_END1("media", "RendererImpl::Initialize",
373 TRACE_ID_LOCAL(this), "status",
374 PipelineStatusToString(status));
375 std::move(init_cb_).Run(status);
378 void RendererImpl::FinishFlush() {
380 TRACE_EVENT_NESTABLE_ASYNC_END0("media", "RendererImpl::Flush",
381 TRACE_ID_LOCAL(this));
382 std::move(flush_cb_).Run();
385 void RendererImpl::InitializeAudioRenderer() {
386 DVLOG(1) << __func__;
387 DCHECK(task_runner_->RunsTasksInCurrentSequence());
388 DCHECK_EQ(state_, STATE_INITIALIZING);
391 // TODO(servolk): Implement proper support for multiple streams. But for now
392 // pick the first enabled stream to preserve the existing behavior.
393 DemuxerStream* audio_stream =
394 media_resource_->GetFirstStream(DemuxerStream::AUDIO);
397 audio_renderer_.reset();
398 task_runner_->PostTask(
399 FROM_HERE, base::BindOnce(&RendererImpl::OnAudioRendererInitializeDone,
400 weak_this_, PIPELINE_OK));
404 current_audio_stream_ = audio_stream;
406 audio_renderer_client_ = std::make_unique<RendererClientInternal>(
407 DemuxerStream::AUDIO, this, media_resource_);
408 // Note: After the initialization of a renderer, error events from it may
409 // happen at any time and all future calls must guard against STATE_ERROR.
410 audio_renderer_->Initialize(
411 audio_stream, cdm_context_, audio_renderer_client_.get(),
412 base::BindOnce(&RendererImpl::OnAudioRendererInitializeDone, weak_this_));
415 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
416 DVLOG(1) << __func__ << ": " << status;
417 DCHECK(task_runner_->RunsTasksInCurrentSequence());
419 // OnError() may be fired at any time by the renderers, even if they thought
420 // they initialized successfully (due to delayed output device setup).
421 if (state_ != STATE_INITIALIZING) {
423 audio_renderer_.reset();
427 if (status != PIPELINE_OK) {
428 FinishInitialization(status);
433 InitializeVideoRenderer();
436 void RendererImpl::InitializeVideoRenderer() {
437 DVLOG(1) << __func__;
438 DCHECK(task_runner_->RunsTasksInCurrentSequence());
439 DCHECK_EQ(state_, STATE_INITIALIZING);
442 // TODO(servolk): Implement proper support for multiple streams. But for now
443 // pick the first enabled stream to preserve the existing behavior.
444 DemuxerStream* video_stream =
445 media_resource_->GetFirstStream(DemuxerStream::VIDEO);
448 video_renderer_.reset();
450 // Something has disabled all audio and video streams, so fail
452 if (!audio_renderer_) {
453 FinishInitialization(PIPELINE_ERROR_COULD_NOT_RENDER);
457 task_runner_->PostTask(
458 FROM_HERE, base::BindOnce(&RendererImpl::OnVideoRendererInitializeDone,
459 weak_this_, PIPELINE_OK));
463 current_video_stream_ = video_stream;
465 video_renderer_client_ = std::make_unique<RendererClientInternal>(
466 DemuxerStream::VIDEO, this, media_resource_);
467 video_renderer_->Initialize(
468 video_stream, cdm_context_, video_renderer_client_.get(),
469 base::BindRepeating(&RendererImpl::GetWallClockTimes,
470 base::Unretained(this)),
471 base::BindOnce(&RendererImpl::OnVideoRendererInitializeDone, weak_this_));
474 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
475 DVLOG(1) << __func__ << ": " << status;
476 DCHECK(task_runner_->RunsTasksInCurrentSequence());
478 // OnError() may be fired at any time by the renderers, even if they thought
479 // they initialized successfully (due to delayed output device setup).
480 if (state_ != STATE_INITIALIZING) {
482 audio_renderer_.reset();
483 video_renderer_.reset();
489 if (status != PIPELINE_OK) {
490 FinishInitialization(status);
494 if (audio_renderer_) {
495 time_source_ = audio_renderer_->GetTimeSource();
496 } else if (!time_source_) {
497 wall_clock_time_source_ = std::make_unique<WallClockTimeSource>();
498 time_source_ = wall_clock_time_source_.get();
501 state_ = STATE_FLUSHED;
502 DCHECK(time_source_);
503 DCHECK(audio_renderer_ || video_renderer_);
505 FinishInitialization(PIPELINE_OK);
508 void RendererImpl::FlushInternal() {
509 DVLOG(1) << __func__;
510 DCHECK(task_runner_->RunsTasksInCurrentSequence());
511 DCHECK_EQ(state_, STATE_FLUSHING);
517 FlushAudioRenderer();
520 // TODO(tmathmeyer) Combine this functionality with track switching flushing.
521 void RendererImpl::FlushAudioRenderer() {
522 DVLOG(1) << __func__;
523 DCHECK(task_runner_->RunsTasksInCurrentSequence());
524 DCHECK_EQ(state_, STATE_FLUSHING);
527 if (!audio_renderer_ || !audio_playing_) {
528 OnAudioRendererFlushDone();
530 audio_renderer_->Flush(
531 base::BindOnce(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
535 void RendererImpl::OnAudioRendererFlushDone() {
536 DVLOG(1) << __func__;
537 DCHECK(task_runner_->RunsTasksInCurrentSequence());
539 if (state_ == STATE_ERROR) {
544 DCHECK_EQ(state_, STATE_FLUSHING);
547 // If we had a deferred video renderer underflow prior to the flush, it should
548 // have been cleared by the audio renderer changing to BUFFERING_HAVE_NOTHING.
549 DCHECK(!has_deferred_buffering_state_change_);
550 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
551 audio_ended_ = false;
552 audio_playing_ = false;
554 FlushVideoRenderer();
557 void RendererImpl::FlushVideoRenderer() {
558 DVLOG(1) << __func__;
559 DCHECK(task_runner_->RunsTasksInCurrentSequence());
560 DCHECK_EQ(state_, STATE_FLUSHING);
563 if (!video_renderer_ || !video_playing_) {
564 OnVideoRendererFlushDone();
566 video_renderer_->Flush(
567 base::BindOnce(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
571 void RendererImpl::OnVideoRendererFlushDone() {
572 DVLOG(1) << __func__;
573 DCHECK(task_runner_->RunsTasksInCurrentSequence());
575 if (state_ == STATE_ERROR) {
580 DCHECK_EQ(state_, STATE_FLUSHING);
583 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
584 video_ended_ = false;
585 video_playing_ = false;
586 state_ = STATE_FLUSHED;
590 void RendererImpl::ReinitializeAudioRenderer(
591 DemuxerStream* stream,
592 base::TimeDelta time,
593 base::OnceClosure reinitialize_completed_cb) {
594 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
595 DCHECK(task_runner_->RunsTasksInCurrentSequence());
596 DCHECK_NE(stream, current_audio_stream_);
598 current_audio_stream_ = stream;
599 audio_renderer_->Initialize(
600 stream, cdm_context_, audio_renderer_client_.get(),
601 base::BindOnce(&RendererImpl::OnAudioRendererReinitialized, weak_this_,
602 stream, time, std::move(reinitialize_completed_cb)));
605 void RendererImpl::OnAudioRendererReinitialized(
606 DemuxerStream* stream,
607 base::TimeDelta time,
608 base::OnceClosure reinitialize_completed_cb,
609 PipelineStatus status) {
610 DVLOG(2) << __func__ << ": status=" << status;
611 DCHECK_EQ(stream, current_audio_stream_);
613 if (status != PIPELINE_OK) {
614 std::move(reinitialize_completed_cb).Run();
618 RestartAudioRenderer(stream, time, std::move(reinitialize_completed_cb));
621 void RendererImpl::ReinitializeVideoRenderer(
622 DemuxerStream* stream,
623 base::TimeDelta time,
624 base::OnceClosure reinitialize_completed_cb) {
625 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
626 DCHECK(task_runner_->RunsTasksInCurrentSequence());
627 DCHECK_NE(stream, current_video_stream_);
629 current_video_stream_ = stream;
630 video_renderer_->OnTimeStopped();
631 video_renderer_->Initialize(
632 stream, cdm_context_, video_renderer_client_.get(),
633 base::BindRepeating(&RendererImpl::GetWallClockTimes,
634 base::Unretained(this)),
635 base::BindOnce(&RendererImpl::OnVideoRendererReinitialized, weak_this_,
636 stream, time, std::move(reinitialize_completed_cb)));
639 void RendererImpl::OnVideoRendererReinitialized(
640 DemuxerStream* stream,
641 base::TimeDelta time,
642 base::OnceClosure reinitialize_completed_cb,
643 PipelineStatus status) {
644 DVLOG(2) << __func__ << ": status=" << status;
645 DCHECK_EQ(stream, current_video_stream_);
647 if (status != PIPELINE_OK) {
648 std::move(reinitialize_completed_cb).Run();
652 RestartVideoRenderer(stream, time, std::move(reinitialize_completed_cb));
655 void RendererImpl::RestartAudioRenderer(
656 DemuxerStream* stream,
657 base::TimeDelta time,
658 base::OnceClosure restart_completed_cb) {
659 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
660 DCHECK(task_runner_->RunsTasksInCurrentSequence());
661 DCHECK(audio_renderer_);
662 DCHECK_EQ(stream, current_audio_stream_);
663 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED ||
664 state_ == STATE_FLUSHING);
666 if (state_ == STATE_FLUSHED) {
667 // If we are in the FLUSHED state, then we are done. The audio renderer will
668 // be restarted by a subsequent RendererImpl::StartPlayingFrom call.
669 std::move(restart_completed_cb).Run();
674 base::AutoLock lock(restarting_audio_lock_);
675 audio_playing_ = true;
676 pending_audio_track_change_ = false;
678 audio_renderer_->StartPlaying();
679 std::move(restart_completed_cb).Run();
682 void RendererImpl::RestartVideoRenderer(
683 DemuxerStream* stream,
684 base::TimeDelta time,
685 base::OnceClosure restart_completed_cb) {
686 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
687 DCHECK(task_runner_->RunsTasksInCurrentSequence());
688 DCHECK(video_renderer_);
689 DCHECK_EQ(stream, current_video_stream_);
690 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED ||
691 state_ == STATE_FLUSHING);
693 if (state_ == STATE_FLUSHED) {
694 // If we are in the FLUSHED state, then we are done. The video renderer will
695 // be restarted by a subsequent RendererImpl::StartPlayingFrom call.
696 std::move(restart_completed_cb).Run();
700 video_playing_ = true;
701 pending_video_track_change_ = false;
702 video_renderer_->StartPlayingFrom(time);
703 std::move(restart_completed_cb).Run();
706 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) {
707 DCHECK(task_runner_->RunsTasksInCurrentSequence());
708 client_->OnStatisticsUpdate(stats);
711 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type,
712 BufferingState new_buffering_state,
713 BufferingStateChangeReason reason) {
714 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO));
715 BufferingState* buffering_state = type == DemuxerStream::AUDIO
716 ? &audio_buffering_state_
717 : &video_buffering_state_;
719 const auto* type_string = DemuxerStream::GetTypeName(type);
720 DVLOG(1) << __func__ << " " << type_string << " "
721 << BufferingStateToString(*buffering_state) << " -> "
722 << BufferingStateToString(new_buffering_state, reason);
723 DCHECK(task_runner_->RunsTasksInCurrentSequence());
724 TRACE_EVENT2("media", "RendererImpl::OnBufferingStateChange", "type",
725 type_string, "state",
726 BufferingStateToString(new_buffering_state, reason));
728 bool was_waiting_for_enough_data = WaitingForEnoughData();
730 if (new_buffering_state == BUFFERING_HAVE_NOTHING) {
731 if ((pending_audio_track_change_ && type == DemuxerStream::AUDIO) ||
732 (pending_video_track_change_ && type == DemuxerStream::VIDEO)) {
733 // Don't pass up a nothing event if it was triggered by a track change.
734 // This would cause the renderer to effectively lie about underflow state.
735 // Even though this might cause an immediate video underflow due to
736 // changing an audio track, all playing is paused when audio is disabled.
737 *buffering_state = new_buffering_state;
742 // When audio is present and has enough data, defer video underflow callbacks
743 // for some time to avoid unnecessary glitches in audio; see
744 // http://crbug.com/144683#c53.
745 if (audio_renderer_ && type == DemuxerStream::VIDEO &&
746 state_ == STATE_PLAYING) {
747 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH &&
748 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH &&
749 new_buffering_state == BUFFERING_HAVE_NOTHING &&
750 !has_deferred_buffering_state_change_) {
751 DVLOG(4) << __func__ << " Deferring HAVE_NOTHING for video stream.";
752 deferred_video_underflow_cb_.Reset(
753 base::BindOnce(&RendererImpl::OnBufferingStateChange, weak_this_,
754 type, new_buffering_state, reason));
755 has_deferred_buffering_state_change_ = true;
756 task_runner_->PostDelayedTask(FROM_HERE,
757 deferred_video_underflow_cb_.callback(),
758 video_underflow_threshold_.value());
762 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()";
763 deferred_video_underflow_cb_.Cancel();
764 has_deferred_buffering_state_change_ = false;
765 } else if (has_deferred_buffering_state_change_ &&
766 type == DemuxerStream::AUDIO &&
767 new_buffering_state == BUFFERING_HAVE_NOTHING) {
768 // If audio underflows while we have a deferred video underflow in progress
769 // we want to mark video as underflowed immediately and cancel the deferral.
770 deferred_video_underflow_cb_.Cancel();
771 has_deferred_buffering_state_change_ = false;
772 video_buffering_state_ = BUFFERING_HAVE_NOTHING;
775 *buffering_state = new_buffering_state;
777 // Disable underflow by ignoring updates that renderers have ran out of data.
778 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
780 DVLOG(1) << "Update ignored because underflow is disabled for testing.";
784 // Renderer underflowed.
785 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
787 client_->OnBufferingStateChange(BUFFERING_HAVE_NOTHING, reason);
791 // Renderer prerolled.
792 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
793 // Prevent condition where audio or video is sputtering and flipping back
794 // and forth between NOTHING and ENOUGH mixing with a track change, causing
795 // a StartPlayback to be called while the audio renderer is being flushed.
796 if (!pending_audio_track_change_ && !pending_video_track_change_) {
798 client_->OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, reason);
804 bool RendererImpl::WaitingForEnoughData() const {
805 DCHECK(task_runner_->RunsTasksInCurrentSequence());
806 if (state_ != STATE_PLAYING)
808 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
810 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
815 void RendererImpl::PausePlayback() {
816 DVLOG(1) << __func__;
817 DCHECK(task_runner_->RunsTasksInCurrentSequence());
818 TRACE_EVENT0("media", "RendererImpl::PausePlayback");
822 DCHECK(PlaybackHasEnded() || WaitingForEnoughData() ||
823 pending_audio_track_change_)
824 << "Playback should only pause due to ending or underflowing or"
825 " when restarting audio stream";
831 // It's OK to pause playback when flushing.
834 case STATE_UNINITIALIZED:
835 case STATE_INIT_PENDING_CDM:
836 case STATE_INITIALIZING:
837 NOTREACHED() << "Invalid state: " << state_;
841 // An error state may occur at any time.
845 time_ticking_ = false;
846 time_source_->StopTicking();
849 if (playback_rate_ > 0 && video_renderer_)
850 video_renderer_->OnTimeStopped();
853 void RendererImpl::StartPlayback() {
854 DVLOG(1) << __func__;
855 DCHECK(task_runner_->RunsTasksInCurrentSequence());
856 DCHECK_EQ(state_, STATE_PLAYING);
857 DCHECK(!WaitingForEnoughData());
858 TRACE_EVENT0("media", "RendererImpl::StartPlayback");
860 if (!time_ticking_) {
861 time_ticking_ = true;
862 audio_playing_ = true;
863 time_source_->StartTicking();
865 if (playback_rate_ > 0 && video_renderer_) {
866 video_playing_ = true;
867 video_renderer_->OnTimeProgressing();
871 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) {
872 const auto* type_string = DemuxerStream::GetTypeName(type);
873 DVLOG(1) << __func__ << ": " << type_string;
874 DCHECK(task_runner_->RunsTasksInCurrentSequence());
875 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO));
876 TRACE_EVENT1("media", "RendererImpl::OnRendererEnded", "type", type_string);
878 // If all streams are ended, do not propagate a redundant ended event.
879 if (state_ != STATE_PLAYING || PlaybackHasEnded())
882 if (type == DemuxerStream::AUDIO) {
883 DCHECK(audio_renderer_);
886 DCHECK(video_renderer_);
888 video_renderer_->OnTimeStopped();
891 RunEndedCallbackIfNeeded();
894 bool RendererImpl::PlaybackHasEnded() const {
895 DCHECK(task_runner_->RunsTasksInCurrentSequence());
897 if (audio_renderer_ && !audio_ended_)
900 if (video_renderer_ && !video_ended_)
906 void RendererImpl::RunEndedCallbackIfNeeded() {
907 DVLOG(1) << __func__;
908 DCHECK(task_runner_->RunsTasksInCurrentSequence());
910 if (!PlaybackHasEnded())
919 void RendererImpl::OnFallback(PipelineStatus fallback) {
920 client_->OnFallback(std::move(fallback).AddHere());
923 void RendererImpl::OnError(PipelineStatus error) {
924 DVLOG(1) << __func__ << "(" << error << ")";
925 DCHECK(task_runner_->RunsTasksInCurrentSequence());
926 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!";
927 TRACE_EVENT1("media", "RendererImpl::OnError", "error",
928 PipelineStatusToString(error));
930 // An error has already been delivered.
931 if (state_ == STATE_ERROR)
934 const State old_state = state_;
935 state_ = STATE_ERROR;
938 DCHECK(old_state == STATE_INITIALIZING ||
939 old_state == STATE_INIT_PENDING_CDM);
940 FinishInitialization(error);
944 // After OnError() returns, the pipeline may destroy |this|.
945 client_->OnError(error);
951 void RendererImpl::OnWaiting(WaitingReason reason) {
952 DCHECK(task_runner_->RunsTasksInCurrentSequence());
953 client_->OnWaiting(reason);
956 void RendererImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
957 DCHECK(task_runner_->RunsTasksInCurrentSequence());
958 client_->OnAudioConfigChange(config);
961 void RendererImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
962 DCHECK(task_runner_->RunsTasksInCurrentSequence());
963 client_->OnVideoConfigChange(config);
966 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
967 DCHECK(task_runner_->RunsTasksInCurrentSequence());
968 client_->OnVideoNaturalSizeChange(size);
971 void RendererImpl::OnVideoOpacityChange(bool opaque) {
972 DCHECK(task_runner_->RunsTasksInCurrentSequence());
973 client_->OnVideoOpacityChange(opaque);
976 void RendererImpl::OnVideoFrameRateChange(absl::optional<int> fps) {
977 DCHECK(task_runner_->RunsTasksInCurrentSequence());
978 client_->OnVideoFrameRateChange(fps);
981 void RendererImpl::CleanUpTrackChange(base::OnceClosure on_finished,
985 // If either stream is alive (i.e. hasn't reached ended state), ended can be
986 // set to false. If both streams are dead, keep ended=true.
987 if ((audio_renderer_ && !audio_ended_) || (video_renderer_ && !video_ended_))
989 std::move(on_finished).Run();
992 void RendererImpl::OnSelectedVideoTracksChanged(
993 const std::vector<DemuxerStream*>& enabled_tracks,
994 base::OnceClosure change_completed_cb) {
995 DCHECK(task_runner_->RunsTasksInCurrentSequence());
996 TRACE_EVENT0("media", "RendererImpl::OnSelectedVideoTracksChanged");
998 DCHECK_LT(enabled_tracks.size(), 2u);
999 DemuxerStream* stream = enabled_tracks.empty() ? nullptr : enabled_tracks[0];
1001 if (!stream && !video_playing_) {
1002 std::move(change_completed_cb).Run();
1006 // 'fixing' the stream -> restarting if its the same stream,
1007 // reinitializing if it is different.
1008 base::OnceClosure fix_stream_cb;
1009 if (stream && stream != current_video_stream_) {
1011 base::BindOnce(&RendererImpl::ReinitializeVideoRenderer, weak_this_,
1012 stream, GetMediaTime(), std::move(change_completed_cb));
1014 fix_stream_cb = base::BindOnce(
1015 &RendererImpl::RestartVideoRenderer, weak_this_, current_video_stream_,
1016 GetMediaTime(), std::move(change_completed_cb));
1019 pending_video_track_change_ = true;
1020 video_renderer_->Flush(base::BindOnce(&RendererImpl::CleanUpTrackChange,
1021 weak_this_, std::move(fix_stream_cb),
1022 &video_ended_, &video_playing_));
1025 void RendererImpl::OnEnabledAudioTracksChanged(
1026 const std::vector<DemuxerStream*>& enabled_tracks,
1027 base::OnceClosure change_completed_cb) {
1028 DCHECK(task_runner_->RunsTasksInCurrentSequence());
1029 TRACE_EVENT0("media", "RendererImpl::OnEnabledAudioTracksChanged");
1031 DCHECK_LT(enabled_tracks.size(), 2u);
1032 DemuxerStream* stream = enabled_tracks.empty() ? nullptr : enabled_tracks[0];
1034 if (!stream && !audio_playing_) {
1035 std::move(change_completed_cb).Run();
1039 // 'fixing' the stream -> restarting if its the same stream,
1040 // reinitializing if it is different.
1041 base::OnceClosure fix_stream_cb;
1043 if (stream && stream != current_audio_stream_) {
1045 base::BindOnce(&RendererImpl::ReinitializeAudioRenderer, weak_this_,
1046 stream, GetMediaTime(), std::move(change_completed_cb));
1048 fix_stream_cb = base::BindOnce(
1049 &RendererImpl::RestartAudioRenderer, weak_this_, current_audio_stream_,
1050 GetMediaTime(), std::move(change_completed_cb));
1054 base::AutoLock lock(restarting_audio_lock_);
1055 pending_audio_track_change_ = true;
1056 restarting_audio_time_ = time_source_->CurrentMediaTime();
1062 audio_renderer_->Flush(base::BindOnce(&RendererImpl::CleanUpTrackChange,
1063 weak_this_, std::move(fix_stream_cb),
1064 &audio_ended_, &audio_playing_));
1067 RendererType RendererImpl::GetRendererType() {
1068 return RendererType::kRendererImpl;
1071 } // namespace media