| Index: chromecast/media/cma/pipeline/media_pipeline_impl.cc
|
| diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
|
| index 68fcaa72e67c5834f50f1e1f40019f885e26603d..49e97d24ac7fba8e224f9e0483fe3bbab8659c7b 100644
|
| --- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
|
| +++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
|
| @@ -51,6 +51,9 @@ const base::TimeDelta kTimeUpdateInterval(
|
| // kTimeUpdateInterval * kStatisticsUpdatePeriod.
|
| const int kStatisticsUpdatePeriod = 4;
|
|
|
| +// Stall duration threshold that triggers a playback stall event.
|
| +constexpr int kPlaybackStallEventThresholdMs = 2500;
|
| +
|
| void LogEstimatedBitrate(int decoded_bytes,
|
| base::TimeDelta elapsed_time,
|
| const char* tag,
|
| @@ -84,9 +87,12 @@ MediaPipelineImpl::MediaPipelineImpl()
|
| audio_decoder_(nullptr),
|
| video_decoder_(nullptr),
|
| pending_time_update_task_(false),
|
| + last_media_time_(::media::kNoTimestamp()),
|
| statistics_rolling_counter_(0),
|
| audio_bytes_for_bitrate_estimation_(0),
|
| video_bytes_for_bitrate_estimation_(0),
|
| + playback_stalled_(false),
|
| + playback_stalled_notification_sent_(false),
|
| weak_factory_(this) {
|
| CMALOG(kLogControl) << __FUNCTION__;
|
| weak_this_ = weak_factory_.GetWeakPtr();
|
| @@ -423,6 +429,55 @@ void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) {
|
| }
|
| }
|
|
|
| +void MediaPipelineImpl::CheckForPlaybackStall(base::TimeDelta media_time,
|
| + base::TimeTicks current_stc) {
|
| + DCHECK(media_time != ::media::kNoTimestamp());
|
| +
|
| + // A playback stall is defined as a scenario where the underlying media
|
| + // pipeline has unexpectedly stopped making forward progress. The pipeline is
|
| + // NOT stalled if:
|
| + //
|
| + // 1. Media time is progressing
|
| + // 2. The backend is paused
|
| + // 3. We are currently buffering (this is captured in a separate event)
|
| + if (media_time != last_media_time_ ||
|
| + backend_state_ != BACKEND_STATE_PLAYING ||
|
| + (buffering_controller_ && buffering_controller_->IsBuffering())) {
|
| + if (playback_stalled_) {
|
| + // Transition out of the stalled condition.
|
| + base::TimeDelta stall_duration = current_stc - playback_stalled_time_;
|
| + CMALOG(kLogControl)
|
| + << "Transitioning out of stalled state. Stall duration was "
|
| + << stall_duration.InMilliseconds() << " ms";
|
| + playback_stalled_ = false;
|
| + playback_stalled_notification_sent_ = false;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + // Check to see if this is a new stall condition.
|
| + if (!playback_stalled_) {
|
| + playback_stalled_ = true;
|
| + playback_stalled_time_ = current_stc;
|
| + return;
|
| + }
|
| +
|
| + // If we are in an existing stall, check to see if we've been stalled for more
|
| + // than 2.5 s. If so, send a single notification of the stall event.
|
| + if (!playback_stalled_notification_sent_) {
|
| + base::TimeDelta current_stall_duration =
|
| + current_stc - playback_stalled_time_;
|
| + if (current_stall_duration.InMilliseconds() >=
|
| + kPlaybackStallEventThresholdMs) {
|
| + CMALOG(kLogControl) << "Playback stalled";
|
| + metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent(
|
| + "Cast.Platform.PlaybackStall");
|
| + playback_stalled_notification_sent_ = true;
|
| + }
|
| + return;
|
| + }
|
| +}
|
| +
|
| void MediaPipelineImpl::UpdateMediaTime() {
|
| pending_time_update_task_ = false;
|
| if ((backend_state_ != BACKEND_STATE_PLAYING) &&
|
| @@ -473,6 +528,8 @@ void MediaPipelineImpl::UpdateMediaTime() {
|
| }
|
| base::TimeTicks stc = base::TimeTicks::Now();
|
|
|
| + CheckForPlaybackStall(media_time, stc);
|
| +
|
| base::TimeDelta max_rendering_time = media_time;
|
| if (buffering_controller_) {
|
| buffering_controller_->SetMediaTime(media_time);
|
|
|