Index: content/renderer/media/video_track_adapter.cc |
diff --git a/content/renderer/media/video_track_adapter.cc b/content/renderer/media/video_track_adapter.cc |
index e51f8427bef23e69f86cae7de12ae5677e2bd70b..13b79bd5e4cacca018a71d97236f458ae002c139 100644 |
--- a/content/renderer/media/video_track_adapter.cc |
+++ b/content/renderer/media/video_track_adapter.cc |
@@ -17,6 +17,12 @@ namespace content { |
namespace { |
+// Amount of frame intervals to wait before considering the source as muted, for |
+// the first frame and under normal conditions, respectively. First frame might |
+// take longer to arrive due to source startup. |
+const float kFirstFrameTimeoutInFrameIntervals = 100.0f; |
+const float kNormalFrameTimeoutInFrameIntervals = 25.0f; |
+ |
// Empty method used for keeping a reference to the original media::VideoFrame |
// in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed. |
// The reference to |frame| is kept in the closure that calls this method. |
@@ -301,7 +307,9 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const { |
VideoTrackAdapter::VideoTrackAdapter( |
const scoped_refptr<base::MessageLoopProxy>& io_message_loop) |
: io_message_loop_(io_message_loop), |
- renderer_task_runner_(base::MessageLoopProxy::current()) { |
+ renderer_task_runner_(base::MessageLoopProxy::current()), |
+ frame_counter_(0), |
+ source_frame_rate_(0.0f) { |
DCHECK(io_message_loop_); |
} |
@@ -309,14 +317,23 @@ VideoTrackAdapter::~VideoTrackAdapter() { |
DCHECK(adapters_.empty()); |
} |
-void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track, |
- VideoCaptureDeliverFrameCB frame_callback, |
- int max_width, |
- int max_height, |
- double min_aspect_ratio, |
- double max_aspect_ratio, |
- double max_frame_rate) { |
+void VideoTrackAdapter::AddTrack( |
+ const MediaStreamVideoTrack* track, |
+ VideoCaptureDeliverFrameCB frame_callback, |
+ int max_width, |
+ int max_height, |
+ double min_aspect_ratio, |
+ double max_aspect_ratio, |
+ double max_frame_rate, |
+ double source_frame_rate, |
+ const OnMutedCallback& on_muted_state_callback) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
+ // Track monitoring should be scheduled before AddTrackOnIO() so it can find |
+ // |adapters_| empty. |
+ io_message_loop_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VideoTrackAdapter::StartTrackMonitoringOnIO, |
+ this, on_muted_state_callback, source_frame_rate)); |
io_message_loop_->PostTask( |
FROM_HERE, |
base::Bind(&VideoTrackAdapter::AddTrackOnIO, |
@@ -360,6 +377,26 @@ void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) { |
base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track)); |
} |
+void VideoTrackAdapter::StartTrackMonitoringOnIO( |
+ const OnMutedCallback& on_muted_state_callback, |
+ double source_frame_rate) { |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ // Only trigger monitoring for the first Track. |
+ if (!adapters_.empty()) |
+ return; |
+ // If the source does not know the frame rate, set one by default. |
+ if (source_frame_rate == 0.0f) |
+ source_frame_rate = MediaStreamVideoSource::kDefaultFrameRate; |
+ source_frame_rate_ = source_frame_rate; |
+ DVLOG(1) << "Monitoring frame creation, first (large) delay: " |
+ << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; |
+ io_message_loop_->PostDelayedTask(FROM_HERE, |
+ base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
+ on_muted_state_callback, frame_counter_), |
+ base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / |
+ source_frame_rate_)); |
+} |
+ |
void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) { |
DCHECK(io_message_loop_->BelongsToCurrentThread()); |
for (FrameAdapters::iterator it = adapters_.begin(); |
@@ -378,10 +415,28 @@ void VideoTrackAdapter::DeliverFrameOnIO( |
const base::TimeTicks& estimated_capture_time) { |
DCHECK(io_message_loop_->BelongsToCurrentThread()); |
TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO"); |
+ ++frame_counter_; |
for (FrameAdapters::iterator it = adapters_.begin(); |
it != adapters_.end(); ++it) { |
(*it)->DeliverFrame(frame, format, estimated_capture_time); |
} |
} |
+void VideoTrackAdapter::CheckFramesReceivedOnIO( |
+ const OnMutedCallback& set_muted_state_callback, |
+ uint64 old_frame_counter_snapshot) { |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_) |
+ << "No frames have passed, setting source as Muted."; |
+ set_muted_state_callback.Run(old_frame_counter_snapshot == frame_counter_); |
+ |
+ // Rearm the monitoring while there are active Tracks, i.e. as long as the |
+ // owner MediaStreamSource is active. |
+ io_message_loop_->PostDelayedTask(FROM_HERE, |
+ base::Bind(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, |
+ set_muted_state_callback, frame_counter_), |
+ base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / |
+ source_frame_rate_)); |
+} |
+ |
} // namespace content |