Chromium Code Reviews| 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..100038a56808d9ab91fb4b50272423db7b7d9e65 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; |
|
alokp
2016/06/03 19:55:28
Add "Ms" suffix to make the unit clear.
ejason
2016/06/03 21:18:31
Done.
|
| + |
| 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() >= |
| + 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 +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); |