OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/download_rate_monitor.h" | 5 #include "media/base/download_rate_monitor.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "testing/gmock/include/gmock/gmock.h" | 9 #include "testing/gmock/include/gmock/gmock.h" |
10 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
11 | 11 |
12 using ::testing::Mock; | 12 using ::testing::Mock; |
13 | 13 |
14 namespace media { | 14 namespace media { |
15 | 15 |
16 class DownloadRateMonitorTest : public ::testing::Test { | 16 class DownloadRateMonitorTest : public ::testing::Test { |
17 public: | 17 public: |
18 DownloadRateMonitorTest() | 18 DownloadRateMonitorTest() { |
19 : canplaythrough_cb_(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, | 19 monitor_.set_total_bytes(kMediaSizeInBytes); |
20 base::Unretained(this))) { } | 20 } |
21 | 21 |
22 virtual ~DownloadRateMonitorTest() { } | 22 virtual ~DownloadRateMonitorTest() { } |
23 | 23 |
24 MOCK_METHOD0(CanPlayThrough, void()); | 24 MOCK_METHOD0(CanPlayThrough, void()); |
25 | 25 |
26 protected: | 26 protected: |
27 static const int kMediaDuration = 120; | 27 static const int kMediaSizeInBytes = 20 * 1024 * 1024; |
28 static const int kMediaBitrate = 1024 * 1024 * 8; | |
29 static const int kMediaByterate = kMediaBitrate / 8; | |
30 static const int kMediaSizeInBytes = kMediaDuration * kMediaByterate; | |
31 static const int kDeferThreshold = 30 * kMediaByterate; | |
32 | 28 |
33 // Simulates downloading |bytes_to_download| bytes of the media file, at | 29 // Simulates downloading of the media file. Packets are timed evenly in |
34 // |download_speed_in_bps| bytes per second. | 30 // |ms_between_packets| intervals, starting at |starting_time|, which is |
35 void SimulateNetwork(int bytes_to_download, int download_speed_in_bps) { | 31 // number of seconds since unix epoch (Jan 1, 1970). |
36 int bytes_downloaded = 0; | 32 // Returns the number of bytes buffered in the media file after the |
37 while (bytes_downloaded < bytes_to_download && | 33 // network activity. |
38 !data_source_.is_deferred()) { | 34 int SimulateNetwork(double starting_time, |
39 int bytes_left_to_download = bytes_to_download - bytes_downloaded; | 35 int starting_bytes, |
40 int packet_size = std::min(download_speed_in_bps, bytes_left_to_download); | 36 int bytes_per_packet, |
41 time_elapsed_ += base::TimeDelta::FromMilliseconds( | 37 int ms_between_packets, |
42 1000 * packet_size / download_speed_in_bps); | 38 int number_of_packets) { |
43 data_source_.ReceiveData( | 39 int bytes_buffered = starting_bytes; |
44 packet_size, time_elapsed_ + base::Time::UnixEpoch()); | 40 base::Time packet_time = base::Time::FromDoubleT(starting_time); |
45 bytes_downloaded += packet_size; | 41 |
| 42 monitor_.SetNetworkActivity(true); |
| 43 // Loop executes (number_of_packets + 1) times because a packet needs a |
| 44 // starting and end point. |
| 45 for (int i = 0; i < number_of_packets + 1; ++i) { |
| 46 monitor_.SetBufferedBytes(bytes_buffered, packet_time); |
| 47 packet_time += base::TimeDelta::FromMilliseconds(ms_between_packets); |
| 48 bytes_buffered += bytes_per_packet; |
46 } | 49 } |
| 50 monitor_.SetNetworkActivity(false); |
| 51 return bytes_buffered; |
47 } | 52 } |
48 | 53 |
49 void Initialize() { | 54 void StartMonitor(int bitrate) { |
50 Initialize(false, false); | 55 StartMonitor(bitrate, false, false); |
51 } | 56 } |
52 | 57 |
53 void Initialize(bool streaming, bool local_source) { | 58 void StartMonitor(int bitrate, bool streaming, bool local_source) { |
54 data_source_.Initialize( | 59 monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, |
55 kMediaBitrate, streaming, local_source, canplaythrough_cb_); | 60 base::Unretained(this)), bitrate, streaming, local_source); |
56 } | 61 } |
57 | 62 |
58 bool DownloadIsDeferred() { | 63 DownloadRateMonitor monitor_; |
59 return data_source_.is_deferred(); | |
60 } | |
61 | |
62 void SeekTo(int offset) { | |
63 data_source_.SeekTo(offset); | |
64 } | |
65 | |
66 // Returns the size of |seconds| seconds of media data in bytes. | |
67 int SecondsToBytes(int seconds) { | |
68 return seconds * kMediaByterate; | |
69 } | |
70 | 64 |
71 private: | 65 private: |
72 // Helper class to simulate a buffered data source. | |
73 class FakeDataSource { | |
74 public: | |
75 FakeDataSource() | |
76 : total_bytes_(kMediaSizeInBytes), | |
77 buffered_bytes_(0), | |
78 offset_(0), | |
79 defer_threshold_(kDeferThreshold), | |
80 is_downloading_data_(true) { } | |
81 | |
82 bool is_deferred() { return !is_downloading_data_; } | |
83 | |
84 void ReceiveData(int bytes_received, base::Time packet_time) { | |
85 CHECK(is_downloading_data_); | |
86 buffered_bytes_ += bytes_received; | |
87 // This simulates that the download is being deferred. | |
88 if (buffered_bytes_ >= defer_threshold_) | |
89 is_downloading_data_ = false; | |
90 | |
91 // Update monitor's state. | |
92 monitor_.SetNetworkActivity(is_downloading_data_); | |
93 monitor_.set_total_bytes(total_bytes_); | |
94 monitor_.SetBufferedBytes(buffered_bytes_ + offset_, packet_time); | |
95 } | |
96 | |
97 void Initialize(int bitrate, bool streaming, bool local_source, | |
98 const base::Closure& canplaythrough_cb) { | |
99 monitor_.Start(canplaythrough_cb, bitrate, streaming, local_source); | |
100 } | |
101 | |
102 void SeekTo(int byte_position) { | |
103 offset_ = byte_position; | |
104 // Simulate recreating the buffer after a seek. | |
105 buffered_bytes_ = 0; | |
106 is_downloading_data_ = true; | |
107 } | |
108 | |
109 private: | |
110 DownloadRateMonitor monitor_; | |
111 | |
112 // Size of the media file being downloaded, in bytes. | |
113 int total_bytes_; | |
114 | |
115 // Number of bytes currently in buffer. | |
116 int buffered_bytes_; | |
117 | |
118 // The byte offset into the file from which the download began. | |
119 int offset_; | |
120 | |
121 // The size of |buffered_bytes_| at which downloading should defer. | |
122 int defer_threshold_; | |
123 | |
124 // True if download is active (not deferred_, false otherwise. | |
125 bool is_downloading_data_; | |
126 }; | |
127 | |
128 FakeDataSource data_source_; | |
129 base::Closure canplaythrough_cb_; | |
130 | |
131 // Amount of time elapsed while downloading data. | |
132 base::TimeDelta time_elapsed_; | |
133 | |
134 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); | 66 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); |
135 }; | 67 }; |
136 | 68 |
137 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { | 69 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { |
| 70 static const int media_bitrate = 1024 * 1024 * 8; |
| 71 |
138 // Simulate downloading at double the media's bitrate. | 72 // Simulate downloading at double the media's bitrate. |
139 Initialize(); | 73 StartMonitor(media_bitrate); |
140 EXPECT_CALL(*this, CanPlayThrough()); | 74 EXPECT_CALL(*this, CanPlayThrough()); |
141 SimulateNetwork(SecondsToBytes(20), 2 * kMediaByterate); | 75 SimulateNetwork(1, 0, 2 * media_bitrate / 8, 1000, 10); |
142 } | 76 } |
143 | 77 |
144 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate_Defer) { | 78 // If the user pauses and the pipeline stops downloading data, make sure the |
145 Initialize(); | 79 // DownloadRateMonitor understands that the download is not stalling. |
| 80 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_Pause) { |
| 81 static const int media_bitrate = 1024 * 1024 * 8; |
| 82 static const int download_byte_rate = 1.1 * media_bitrate / 8; |
146 | 83 |
147 // Download slower than the media's bitrate, but buffer enough data such that | 84 // Start downloading faster than the media's bitrate. |
148 // the data source defers. | 85 StartMonitor(media_bitrate); |
149 EXPECT_CALL(*this, CanPlayThrough()); | 86 EXPECT_CALL(*this, CanPlayThrough()); |
150 SimulateNetwork(kDeferThreshold, 0.3 * kMediaByterate); | 87 int buffered = SimulateNetwork(1, 0, download_byte_rate, 1000, 2); |
151 CHECK(DownloadIsDeferred()); | 88 |
| 89 // Then "pause" for 3 minutes and continue downloading at same rate. |
| 90 SimulateNetwork(60 * 3, buffered, download_byte_rate, 1000, 4); |
152 } | 91 } |
153 | 92 |
154 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) { | 93 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) { |
| 94 static const int media_bitrate = 1024 * 1024 * 8; |
| 95 static const int download_byte_rate = 1.1 * media_bitrate / 8; |
| 96 |
155 // Start downloading faster than the media's bitrate. | 97 // Start downloading faster than the media's bitrate. |
156 Initialize(); | 98 EXPECT_CALL(*this, CanPlayThrough()); |
157 SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate); | 99 StartMonitor(media_bitrate); |
| 100 SimulateNetwork(1, 0, download_byte_rate, 1000, 2); |
158 | 101 |
159 // Then seek forward mid-file and continue downloading at same rate. | 102 // Then seek forward mid-file and continue downloading at same rate. |
160 SeekTo(kMediaSizeInBytes / 2); | 103 SimulateNetwork(4, kMediaSizeInBytes / 2, download_byte_rate, 1000, 4); |
161 EXPECT_CALL(*this, CanPlayThrough()); | |
162 SimulateNetwork(7 * kMediaByterate, 1.1 * kMediaByterate); | |
163 | |
164 // Verify deferring is not what caused CanPlayThrough to fire. | |
165 CHECK(!DownloadIsDeferred()); | |
166 } | 104 } |
167 | 105 |
168 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) { | 106 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) { |
| 107 static const int media_bitrate = 1024 * 1024 * 8; |
| 108 static const int download_byte_rate = 1.1 * media_bitrate / 8; |
| 109 |
169 // Start downloading faster than the media's bitrate, in middle of file. | 110 // Start downloading faster than the media's bitrate, in middle of file. |
170 Initialize(); | 111 StartMonitor(media_bitrate); |
171 SeekTo(kMediaSizeInBytes / 2); | 112 SimulateNetwork(1, kMediaSizeInBytes / 2, download_byte_rate, 1000, 2); |
172 SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate); | |
173 | 113 |
174 // Then seek back to beginning and continue downloading at same rate. | 114 // Then seek back to beginning and continue downloading at same rate. |
175 SeekTo(0); | |
176 EXPECT_CALL(*this, CanPlayThrough()); | 115 EXPECT_CALL(*this, CanPlayThrough()); |
177 SimulateNetwork(SecondsToBytes(7), 1.1 * kMediaByterate); | 116 SimulateNetwork(4, 0, download_byte_rate, 1000, 4); |
178 | |
179 // Verify deferring is not what caused CanPlayThrough to fire. | |
180 CHECK(!DownloadIsDeferred()); | |
181 } | 117 } |
182 | 118 |
183 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanByterate) { | 119 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) { |
| 120 static const int media_bitrate = 1024 * 1024 * 8; |
| 121 |
184 // Simulate downloading at half the media's bitrate. | 122 // Simulate downloading at half the media's bitrate. |
185 EXPECT_CALL(*this, CanPlayThrough()) | 123 EXPECT_CALL(*this, CanPlayThrough()) |
186 .Times(0); | 124 .Times(0); |
187 Initialize(); | 125 StartMonitor(media_bitrate); |
188 SimulateNetwork(SecondsToBytes(10), kMediaByterate / 2); | 126 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, 10); |
189 } | 127 } |
190 | 128 |
191 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { | 129 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { |
| 130 static const int media_bitrate = 1024 * 1024 * 8; |
| 131 |
192 // Simulate no data downloaded. | 132 // Simulate no data downloaded. |
193 EXPECT_CALL(*this, CanPlayThrough()); | 133 EXPECT_CALL(*this, CanPlayThrough()); |
194 Initialize(false, true); | 134 StartMonitor(media_bitrate, false, true); |
195 } | 135 } |
196 | 136 |
197 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { | 137 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { |
| 138 static const int media_bitrate = 1024 * 1024 * 8; |
| 139 |
198 // Simulate downloading at the media's bitrate while streaming. | 140 // Simulate downloading at the media's bitrate while streaming. |
199 EXPECT_CALL(*this, CanPlayThrough()); | 141 EXPECT_CALL(*this, CanPlayThrough()); |
200 Initialize(true, false); | 142 StartMonitor(media_bitrate, true, false); |
201 SimulateNetwork(SecondsToBytes(10), kMediaByterate); | 143 SimulateNetwork(1, 0, media_bitrate / 8, 1000, 10); |
202 } | 144 } |
203 | 145 |
204 TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { | 146 TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { |
| 147 static const int media_bitrate = 1024 * 1024 * 8; |
| 148 |
205 // Simulate downloading half the video very quickly in one chunk. | 149 // Simulate downloading half the video very quickly in one chunk. |
206 Initialize(); | 150 StartMonitor(media_bitrate); |
207 EXPECT_CALL(*this, CanPlayThrough()); | 151 EXPECT_CALL(*this, CanPlayThrough()); |
208 SimulateNetwork(kMediaSizeInBytes / 2, kMediaSizeInBytes * 10); | 152 SimulateNetwork(1, 0, kMediaSizeInBytes / 2, 10, 1); |
209 } | 153 } |
210 | 154 |
211 TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { | 155 TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { |
| 156 static const int seconds_of_data = 20; |
| 157 static const int media_bitrate = kMediaSizeInBytes * 8 / seconds_of_data; |
| 158 |
212 // Simulate downloading entire video at half the bitrate of the video. | 159 // Simulate downloading entire video at half the bitrate of the video. |
213 Initialize(); | 160 StartMonitor(media_bitrate); |
214 EXPECT_CALL(*this, CanPlayThrough()); | 161 EXPECT_CALL(*this, CanPlayThrough()); |
215 SimulateNetwork(kMediaSizeInBytes, kMediaByterate / 2); | 162 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, seconds_of_data * 2); |
216 } | |
217 | |
218 TEST_F(DownloadRateMonitorTest, DownloadEndOfVideo) { | |
219 Initialize(); | |
220 // Seek to 10s before the end of the file, then download the remainder of the | |
221 // file at half the bitrate. | |
222 SeekTo((kMediaDuration - 10) * kMediaByterate); | |
223 EXPECT_CALL(*this, CanPlayThrough()); | |
224 SimulateNetwork(SecondsToBytes(10), kMediaByterate/ 2); | |
225 | |
226 // Verify deferring is not what caused CanPlayThrough to fire. | |
227 CHECK(!DownloadIsDeferred()); | |
228 } | 163 } |
229 | 164 |
230 } // namespace media | 165 } // namespace media |
OLD | NEW |