Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: media/base/download_rate_monitor.cc

Issue 8399023: Fire canplaythrough event at the proper time for audio/video (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove unneeded bool Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/download_rate_monitor.h"
6
7 #include "base/bind.h"
8 #include "base/time.h"
9
10 namespace media {
11
12 // Number of samples to use to collect and average for each measurement of
13 // download rate.
14 static const size_t kNumberOfSamples = 5;
15
16 // Minimum number of seconds represented in a sample period.
17 static const float kSamplePeriod = 1.0;
18
19 DownloadRateMonitor::Sample::Sample() {
20 Reset();
21 }
22
23 DownloadRateMonitor::Sample::Sample(
24 const BufferingPoint& start, const BufferingPoint& end) {
25 Reset();
26 start_ = start;
27 set_end(end);
28 }
29
30 void DownloadRateMonitor::Sample::set_end(const BufferingPoint& new_end) {
31 DCHECK(!start_.timestamp.is_null());
32 DCHECK(new_end.buffered_bytes >= start_.buffered_bytes);
33 DCHECK(new_end.timestamp >= start_.timestamp);
34 end_ = new_end;
35 }
36
37 float DownloadRateMonitor::Sample::bytes_per_second() const {
38 if (seconds_elapsed() > 0.0 && bytes_downloaded() >= 0)
39 return bytes_downloaded() / seconds_elapsed();
40 return -1.0;
41 }
42
43 float DownloadRateMonitor::Sample::seconds_elapsed() const {
44 if (start_.timestamp.is_null() || end_.timestamp.is_null())
45 return -1.0;
46 return (end_.timestamp - start_.timestamp).InSecondsF();
47 }
48
49 int64 DownloadRateMonitor::Sample::bytes_downloaded() const {
50 if (start_.timestamp.is_null() || end_.timestamp.is_null())
51 return -1.0;
52 return end_.buffered_bytes - start_.buffered_bytes;
53 }
54
55 bool DownloadRateMonitor::Sample::is_null() const {
56 return start_.timestamp.is_null() && end_.timestamp.is_null();
57 }
58
59 void DownloadRateMonitor::Sample::Reset() {
60 start_ = BufferingPoint();
61 end_ = BufferingPoint();
62 }
63
64 void DownloadRateMonitor::Sample::RestartAtEndBufferingPoint() {
65 start_ = end_;
66 end_ = BufferingPoint();
67 }
68
69 DownloadRateMonitor::DownloadRateMonitor() {
70 Reset();
71 }
72
73 void DownloadRateMonitor::Start(
74 const CanPlayThroughCB& canplaythrough_cb, int media_bitrate) {
75 DCHECK(stopped_);
76 canplaythrough_cb_ = canplaythrough_cb;
77 stopped_ = false;
78 bitrate_ = media_bitrate;
79 current_sample_.Reset();
80 buffered_bytes_ = 0;
81
82 NotifyCanPlayThroughIfNeeded();
83 }
84
85 void DownloadRateMonitor::SetBufferedBytes(
86 int64 buffered_bytes, const base::Time& timestamp) {
87 if (stopped_)
88 return;
89
90 is_downloading_data_ = true;
91
92 // Check monotonically nondecreasing constraint.
93 if (current_sample_.is_null())
94 DCHECK(timestamp >= current_sample_.end().timestamp);
95 else if (!sample_window_.empty())
96 DCHECK(timestamp >= sample_window_.back().end().timestamp);
97
98 // If the buffer level has dropped, invalidate current sample.
99 if (buffered_bytes < buffered_bytes_)
100 current_sample_.Reset();
101 buffered_bytes_ = buffered_bytes;
102
103 BufferingPoint latest_point = { buffered_bytes, timestamp };
104 if (current_sample_.is_null())
105 current_sample_ = Sample(latest_point, latest_point);
106 else
107 current_sample_.set_end(latest_point);
108
109 UpdateSampleWindow();
110 NotifyCanPlayThroughIfNeeded();
111 }
112
113 void DownloadRateMonitor::SetNetworkActivity(bool is_downloading_data) {
114 if (is_downloading_data == is_downloading_data_)
115 return;
116 // Invalidate the current sample if downloading is going from start to stopped
117 // or vice versa.
118 current_sample_.Reset();
119 is_downloading_data_ = is_downloading_data;
120 }
121
122 void DownloadRateMonitor::Stop() {
123 stopped_ = true;
124 current_sample_.Reset();
125 buffered_bytes_ = 0;
126 }
127
128 void DownloadRateMonitor::Reset() {
129 canplaythrough_cb_.Reset();
130 has_notified_can_play_through_ = false;
131 current_sample_.Reset();
132 sample_window_.clear();
133 is_downloading_data_ = false;
134 total_bytes_ = 0;
135 buffered_bytes_ = 0;
136 loaded_ = false;
137 bitrate_ = 0;
138 stopped_ = true;
139 }
140
141 int64 DownloadRateMonitor::bytes_downloaded_in_window() const {
142 // There are max |kNumberOfSamples| so we might as well recompute each time.
143 int64 total = 0;
144 for (size_t i = 0; i < sample_window_.size(); ++i)
145 total += sample_window_[i].bytes_downloaded();
146 return total;
147 }
148
149 float DownloadRateMonitor::seconds_elapsed_in_window() const {
150 // There are max |kNumberOfSamples| so we might as well recompute each time.
151 float total = 0.0;
152 for (size_t i = 0; i < sample_window_.size(); ++i)
153 total += sample_window_[i].seconds_elapsed();
154 return total;
155 }
156
157 void DownloadRateMonitor::UpdateSampleWindow() {
158 if (current_sample_.seconds_elapsed() < kSamplePeriod)
159 return;
160
161 // Add latest sample and remove oldest sample.
162 sample_window_.push_back(current_sample_);
163 if (sample_window_.size() > kNumberOfSamples)
164 sample_window_.pop_front();
165
166 // Prepare for next measurement.
167 current_sample_.RestartAtEndBufferingPoint();
168 }
169
170 float DownloadRateMonitor::ApproximateDownloadByteRate() const {
171 // Compute and return the average download byte rate from within the sample
172 // window.
173 // XXX: If the data is arriving really bursty-ly, say getting a big chunk
174 // of data every 5 seconds, then with this implementation it will take 25
175 // seconds until bitrate is calculated ... is that ok?
176 if (sample_window_.size() >= kNumberOfSamples) {
177 DCHECK(seconds_elapsed_in_window() > 0.0);
178 if (seconds_elapsed_in_window() > 0.0)
acolwell GONE FROM CHROMIUM 2011/11/11 21:05:39 remove DCHECK or if depending on whether you think
vrk (LEFT CHROMIUM) 2011/11/15 16:55:16 Done.
179 return bytes_downloaded_in_window() / seconds_elapsed_in_window();
180 }
181
182 // Could not determine approximate download byte rate.
183 return -1.0;
184 }
185
186 bool DownloadRateMonitor::ShouldNotifyCanPlayThrough() {
187 // A stream with |total_bytes_| == 0 means the size of the stream cannot be
188 // determined or is undefined in the streaming case. In these scenarios,
189 // CanPlayThrough should never fire.
190 if (has_notified_can_play_through_ || total_bytes_ == 0)
191 return false;
192
193 // If the media is from a local file (|loaded_|) or if all bytes are
194 // buffered, fire CanPlayThrough.
195 if (loaded_ || buffered_bytes_ == total_bytes_)
196 return true;
197
198 // Cannot approximate when the media can play through if bitrate is unknown.
199 if (bitrate_ <= 0)
200 return false;
201
202 float bytes_needed_per_second = bitrate_ / 8;
203 float download_rate = ApproximateDownloadByteRate();
204
205 // If we are downloading at or faster than the media's bitrate, then we can
206 // play through to the end of the media without stopping to buffer.
207 if (download_rate > 0)
208 return download_rate > bytes_needed_per_second;
209
210 // If download rate is unknown, it may be because the media is being
211 // downloaded so fast that it cannot collect an adequate number of samples
212 // before the download gets deferred.
213 //
214 // To catch this case, we also look at how much data is being downloaded
215 // immediately after the download begins.
216 if (sample_window_.size() < kNumberOfSamples) {
217 int64 bytes_downloaded_since_start =
218 bytes_downloaded_in_window() + current_sample_.bytes_downloaded();
219 float seconds_elapsed_since_start =
220 seconds_elapsed_in_window() + current_sample_.seconds_elapsed();
221
222 // If we download 4 seconds of data in less than 2 seconds of time, we're
223 // probably downloading at a fast enough rate that we can play through.
224 // This is an arbitrary metric that will likely need tweaking.
225 if (seconds_elapsed_since_start < 2.0 &&
226 bytes_downloaded_since_start > 4.0 * bytes_needed_per_second) {
227 return true;
228 }
229 }
230
231 return false;
232 }
233
234 void DownloadRateMonitor::NotifyCanPlayThroughIfNeeded() {
235 if (ShouldNotifyCanPlayThrough() && !canplaythrough_cb_.is_null()) {
236 canplaythrough_cb_.Run();
237 has_notified_can_play_through_ = true;
238 }
239 }
240
241 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698