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..7f326364527291746de82f1c2ba054d412895bdd 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 kPlaybackStallEventThreshold = 2500; |
+ |
void LogEstimatedBitrate(int decoded_bytes, |
base::TimeDelta elapsed_time, |
const char* tag, |
@@ -87,6 +90,8 @@ MediaPipelineImpl::MediaPipelineImpl() |
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 +428,55 @@ void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) { |
} |
} |
+void MediaPipelineImpl::CheckForPlaybackStall(base::TimeDelta media_time, |
+ base::TimeTicks current_stc) { |
kmackay
2016/06/03 17:37:05
what does 'stc' stand for?
ejason
2016/06/03 19:20:15
System time clock. I simply re-used the existing n
|
+ 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() >= |
+ kPlaybackStallEventThreshold) { |
+ 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 +527,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); |