Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 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 monitor_.set_total_bytes(kMediaSizeInBytes); | 19 : canplaythrough_cb_(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, |
| 20 base::Unretained(this))) { | |
| 21 data_source_.reset( | |
| 22 new FakeDataSource(kMediaSizeInBytes, kDeferThreshold, 0, &host_)); | |
| 20 } | 23 } |
| 21 | 24 |
| 22 virtual ~DownloadRateMonitorTest() { } | 25 virtual ~DownloadRateMonitorTest() { } |
| 23 | 26 |
| 24 MOCK_METHOD0(CanPlayThrough, void()); | 27 MOCK_METHOD0(CanPlayThrough, void()); |
| 25 | 28 |
| 26 protected: | 29 protected: |
| 27 static const int kMediaSizeInBytes = 20 * 1024 * 1024; | 30 static const int kMediaDuration = 120; |
| 31 static const int kMediaBitrate = 1024 * 1024 * 8; | |
| 32 static const int kMediaByterate = kMediaBitrate / 8; | |
| 33 static const int kMediaSizeInBytes = kMediaDuration * kMediaByterate; | |
| 34 static const int kDeferThreshold = 30 * kMediaByterate; | |
| 28 | 35 |
| 29 // Simulates downloading of the media file. Packets are timed evenly in | 36 // Simulates downloading of the media file. Packets are timed evenly in |
| 30 // |ms_between_packets| intervals, starting at |starting_time|, which is | 37 // |ms_between_packets| intervals, starting at |starting_time|, which is |
| 31 // number of seconds since unix epoch (Jan 1, 1970). | 38 // number of seconds since unix epoch (Jan 1, 1970). |
| 32 // Returns the number of bytes buffered in the media file after the | 39 // Returns the number of bytes buffered in the media file after the |
| 33 // network activity. | 40 // network activity. |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
Is this last sentence true still? Isn't the return
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
No longer true, but n/a now.
| |
| 34 int SimulateNetwork(double starting_time, | 41 int SimulateNetwork(double starting_time, int bytes_per_packet, |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
I think this signature still makes the tests a lit
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
Yes, a lot cleaner! Thanks, done!
| |
| 35 int starting_bytes, | 42 int ms_between_packets, int number_of_packets) { |
| 36 int bytes_per_packet, | 43 int bytes_buffered = 0; |
| 37 int ms_between_packets, | |
| 38 int number_of_packets) { | |
| 39 int bytes_buffered = starting_bytes; | |
| 40 base::Time packet_time = base::Time::FromDoubleT(starting_time); | 44 base::Time packet_time = base::Time::FromDoubleT(starting_time); |
| 41 | 45 |
| 42 monitor_.SetNetworkActivity(true); | |
| 43 // Loop executes (number_of_packets + 1) times because a packet needs a | 46 // Loop executes (number_of_packets + 1) times because a packet needs a |
| 44 // starting and end point. | 47 // starting and end point. |
| 45 for (int i = 0; i < number_of_packets + 1; ++i) { | 48 for (int i = 0; i < number_of_packets + 1; ++i) { |
| 46 monitor_.SetBufferedBytes(bytes_buffered, packet_time); | 49 if (data_source_->is_deferred()) |
| 50 break; | |
| 51 | |
| 52 data_source_->ReceiveData(bytes_per_packet, packet_time); | |
| 53 bytes_buffered += bytes_per_packet; | |
| 54 | |
| 47 packet_time += base::TimeDelta::FromMilliseconds(ms_between_packets); | 55 packet_time += base::TimeDelta::FromMilliseconds(ms_between_packets); |
| 48 bytes_buffered += bytes_per_packet; | 56 } |
| 49 } | |
| 50 monitor_.SetNetworkActivity(false); | |
| 51 return bytes_buffered; | 57 return bytes_buffered; |
| 52 } | 58 } |
| 53 | 59 |
| 54 void StartMonitor(int bitrate) { | 60 void Initialize() { |
| 55 StartMonitor(bitrate, false, false); | 61 Initialize(false, false); |
| 56 } | 62 } |
| 57 | 63 |
| 58 void StartMonitor(int bitrate, bool streaming, bool local_source) { | 64 void Initialize(bool streaming, bool local_source) { |
| 59 monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, | 65 host_.Initialize( |
| 60 base::Unretained(this)), bitrate, streaming, local_source); | 66 kMediaBitrate, streaming, local_source, canplaythrough_cb_); |
| 61 } | 67 } |
| 62 | 68 |
| 63 DownloadRateMonitor monitor_; | 69 void SeekTo(int byte_position) { |
| 70 data_source_.reset(new FakeDataSource( | |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
Consider converting this to a Seek() method on Fak
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
Yeah, I think I was trying too hard to replicate w
| |
| 71 kMediaSizeInBytes, kDeferThreshold, byte_position, &host_)); | |
| 72 } | |
| 73 | |
| 74 bool DownloadIsDeferred() { | |
| 75 return data_source_->is_deferred(); | |
| 76 } | |
| 64 | 77 |
| 65 private: | 78 private: |
| 79 // Helper class that simulates the filter host that owns and communicates with | |
| 80 // the |monitor_|. | |
| 81 class FakeFilterHost { | |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
I think you should just put these methods in FakeD
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
Done.
| |
| 82 public: | |
| 83 void UpdateHostState(bool is_downloading_data, int total_bytes, | |
| 84 int buffered_bytes, base::Time last_packet_time) { | |
| 85 monitor_.SetNetworkActivity(is_downloading_data); | |
| 86 monitor_.set_total_bytes(total_bytes); | |
| 87 monitor_.SetBufferedBytes(buffered_bytes, last_packet_time); | |
| 88 } | |
| 89 | |
| 90 void Initialize(int bitrate, bool streaming, bool local_source, | |
| 91 const base::Closure& canplaythrough_cb) { | |
| 92 monitor_.Start(canplaythrough_cb, bitrate, streaming, local_source); | |
| 93 } | |
| 94 | |
| 95 private: | |
| 96 DownloadRateMonitor monitor_; | |
| 97 }; | |
| 98 | |
| 99 // Helper class to simulate a buffered data source. | |
| 100 class FakeDataSource { | |
| 101 public: | |
| 102 FakeDataSource(int total_bytes, int defer_threshold, int offset, | |
| 103 FakeFilterHost* host) | |
| 104 : total_bytes_(total_bytes), | |
| 105 buffered_bytes_(0), | |
| 106 offset_(offset), | |
| 107 host_(host), | |
| 108 defer_threshold_(defer_threshold), | |
| 109 is_downloading_data_(true) { } | |
| 110 | |
| 111 bool is_deferred() { return !is_downloading_data_; } | |
| 112 | |
| 113 void ReceiveData(int bytes_received, base::Time packet_time) { | |
| 114 CHECK(is_downloading_data_); | |
| 115 buffered_bytes_ += bytes_received; | |
| 116 if (buffered_bytes_ > defer_threshold_) | |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
How about a comment stating that you are simulatin
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
Done.
| |
| 117 is_downloading_data_ = false; | |
| 118 host_->UpdateHostState(is_downloading_data_, total_bytes_, | |
| 119 buffered_bytes_ + offset_, packet_time); | |
| 120 } | |
| 121 | |
| 122 private: | |
| 123 // Size of the media file being downloaded, in bytes. | |
| 124 int total_bytes_; | |
| 125 | |
| 126 // Number of bytes currently in buffer. | |
| 127 int buffered_bytes_; | |
| 128 | |
| 129 // The byte offset into the file from which the download began. | |
| 130 int offset_; | |
| 131 | |
| 132 // Unowned reference to the filter host. | |
| 133 FakeFilterHost* host_; | |
| 134 | |
| 135 // The size of |buffered_bytes_| at which downloading should defer. | |
| 136 int defer_threshold_; | |
| 137 | |
| 138 // True if download is active (not deferred_, false otherwise. | |
| 139 bool is_downloading_data_; | |
| 140 }; | |
| 141 | |
| 142 FakeFilterHost host_; | |
| 143 scoped_ptr<FakeDataSource> data_source_; | |
| 144 base::Closure canplaythrough_cb_; | |
| 145 | |
| 66 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); | 146 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); |
| 67 }; | 147 }; |
| 68 | 148 |
| 69 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { | 149 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { |
| 70 static const int media_bitrate = 1024 * 1024 * 8; | |
| 71 | |
| 72 // Simulate downloading at double the media's bitrate. | 150 // Simulate downloading at double the media's bitrate. |
| 73 StartMonitor(media_bitrate); | 151 Initialize(); |
| 74 EXPECT_CALL(*this, CanPlayThrough()); | 152 EXPECT_CALL(*this, CanPlayThrough()); |
| 75 SimulateNetwork(1, 0, 2 * media_bitrate / 8, 1000, 10); | 153 SimulateNetwork(1, 2 * kMediaByterate, 1000, 10); |
| 76 } | 154 } |
| 77 | 155 |
| 78 // If the user pauses and the pipeline stops downloading data, make sure the | 156 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate_Defer) { |
| 79 // DownloadRateMonitor understands that the download is not stalling. | 157 Initialize(); |
| 80 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_Pause) { | 158 |
| 81 static const int media_bitrate = 1024 * 1024 * 8; | 159 // Download slower than the media's bitrate, but buffer enough data such that |
| 82 static const int download_byte_rate = 1.1 * media_bitrate / 8; | 160 // the data source defers. |
| 83 | 161 int bytes_buffered = 0; |
| 162 EXPECT_CALL(*this, CanPlayThrough()); | |
| 163 int time = 1; | |
| 164 while(bytes_buffered < kDeferThreshold) { | |
| 165 int downloaded_bytes = | |
| 166 SimulateNetwork(time++, 0.3 * kMediaByterate, 1000, 1); | |
| 167 if (downloaded_bytes == 0) | |
| 168 break; | |
| 169 bytes_buffered += downloaded_bytes; | |
| 170 } | |
| 171 CHECK(DownloadIsDeferred()); | |
| 172 } | |
| 173 | |
| 174 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) { | |
| 84 // Start downloading faster than the media's bitrate. | 175 // Start downloading faster than the media's bitrate. |
| 85 StartMonitor(media_bitrate); | 176 Initialize(); |
| 86 EXPECT_CALL(*this, CanPlayThrough()); | 177 SimulateNetwork(1, 1.1 * kMediaByterate, 1000, 2); |
| 87 int buffered = SimulateNetwork(1, 0, download_byte_rate, 1000, 2); | |
| 88 | |
| 89 // Then "pause" for 3 minutes and continue downloading at same rate. | |
| 90 SimulateNetwork(60 * 3, buffered, download_byte_rate, 1000, 4); | |
| 91 } | |
| 92 | |
| 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 | |
| 97 // Start downloading faster than the media's bitrate. | |
| 98 EXPECT_CALL(*this, CanPlayThrough()); | |
| 99 StartMonitor(media_bitrate); | |
| 100 SimulateNetwork(1, 0, download_byte_rate, 1000, 2); | |
| 101 | 178 |
| 102 // Then seek forward mid-file and continue downloading at same rate. | 179 // Then seek forward mid-file and continue downloading at same rate. |
| 103 SimulateNetwork(4, kMediaSizeInBytes / 2, download_byte_rate, 1000, 4); | 180 SeekTo(kMediaSizeInBytes / 2); |
| 181 EXPECT_CALL(*this, CanPlayThrough()); | |
| 182 SimulateNetwork(4, 1.1 * kMediaByterate, 1000, 4); | |
| 183 | |
| 184 // CanPlayThrough should not be fired because of deferring. | |
| 185 CHECK(!DownloadIsDeferred()); | |
| 104 } | 186 } |
| 105 | 187 |
| 106 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) { | 188 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 | |
| 110 // Start downloading faster than the media's bitrate, in middle of file. | 189 // Start downloading faster than the media's bitrate, in middle of file. |
| 111 StartMonitor(media_bitrate); | 190 Initialize(); |
| 112 SimulateNetwork(1, kMediaSizeInBytes / 2, download_byte_rate, 1000, 2); | 191 SeekTo(kMediaSizeInBytes / 2); |
| 192 SimulateNetwork(1, 1.1 * kMediaByterate, 1000, 2); | |
| 113 | 193 |
| 114 // Then seek back to beginning and continue downloading at same rate. | 194 // Then seek back to beginning and continue downloading at same rate. |
| 115 EXPECT_CALL(*this, CanPlayThrough()); | 195 SeekTo(0); |
| 116 SimulateNetwork(4, 0, download_byte_rate, 1000, 4); | 196 EXPECT_CALL(*this, CanPlayThrough()); |
| 197 SimulateNetwork(4, 1.1 * kMediaByterate, 1000, 4); | |
| 198 | |
| 199 // CanPlayThrough should not be fired because of deferring. | |
| 200 CHECK(!DownloadIsDeferred()); | |
| 117 } | 201 } |
| 118 | 202 |
| 119 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) { | 203 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) { |
| 120 static const int media_bitrate = 1024 * 1024 * 8; | |
| 121 | |
| 122 // Simulate downloading at half the media's bitrate. | 204 // Simulate downloading at half the media's bitrate. |
| 123 EXPECT_CALL(*this, CanPlayThrough()) | 205 EXPECT_CALL(*this, CanPlayThrough()) |
| 124 .Times(0); | 206 .Times(0); |
| 125 StartMonitor(media_bitrate); | 207 Initialize(); |
| 126 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, 10); | 208 SimulateNetwork(1, kMediaByterate / 2, 1000, 10); |
| 127 } | 209 } |
| 128 | 210 |
| 129 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { | 211 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { |
| 130 static const int media_bitrate = 1024 * 1024 * 8; | |
| 131 | |
| 132 // Simulate no data downloaded. | 212 // Simulate no data downloaded. |
| 133 EXPECT_CALL(*this, CanPlayThrough()); | 213 EXPECT_CALL(*this, CanPlayThrough()); |
| 134 StartMonitor(media_bitrate, false, true); | 214 Initialize(false, true); |
| 135 } | 215 } |
| 136 | 216 |
| 137 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { | 217 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { |
| 138 static const int media_bitrate = 1024 * 1024 * 8; | |
| 139 | |
| 140 // Simulate downloading at the media's bitrate while streaming. | 218 // Simulate downloading at the media's bitrate while streaming. |
| 141 EXPECT_CALL(*this, CanPlayThrough()); | 219 EXPECT_CALL(*this, CanPlayThrough()); |
| 142 StartMonitor(media_bitrate, true, false); | 220 Initialize(true, false); |
| 143 SimulateNetwork(1, 0, media_bitrate / 8, 1000, 10); | 221 SimulateNetwork(1, kMediaByterate, 1000, 10); |
| 144 } | 222 } |
| 145 | 223 |
| 146 TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { | 224 TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { |
| 147 static const int media_bitrate = 1024 * 1024 * 8; | |
| 148 | |
| 149 // Simulate downloading half the video very quickly in one chunk. | 225 // Simulate downloading half the video very quickly in one chunk. |
| 150 StartMonitor(media_bitrate); | 226 Initialize(); |
| 151 EXPECT_CALL(*this, CanPlayThrough()); | 227 EXPECT_CALL(*this, CanPlayThrough()); |
| 152 SimulateNetwork(1, 0, kMediaSizeInBytes / 2, 10, 1); | 228 SimulateNetwork(1, kMediaSizeInBytes / 2, 10, 1); |
| 153 } | 229 } |
| 154 | 230 |
| 155 TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { | 231 TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { |
| 156 static const int seconds_of_data = 20; | |
| 157 static const int media_bitrate = kMediaSizeInBytes * 8 / seconds_of_data; | |
| 158 | |
| 159 // Simulate downloading entire video at half the bitrate of the video. | 232 // Simulate downloading entire video at half the bitrate of the video. |
| 160 StartMonitor(media_bitrate); | 233 Initialize(); |
| 161 EXPECT_CALL(*this, CanPlayThrough()); | 234 EXPECT_CALL(*this, CanPlayThrough()); |
| 162 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, seconds_of_data * 2); | 235 SimulateNetwork(1, kMediaByterate / 2, 1000, kMediaDuration * 2); |
| 236 } | |
| 237 | |
| 238 TEST_F(DownloadRateMonitorTest, DownloadEndOfVideo) { | |
| 239 Initialize(); | |
| 240 // Seek to 10s before the end of the file, then download the remainder of the | |
| 241 // file at half the bitrate. | |
| 242 SeekTo((kMediaDuration - 10) * kMediaByterate); | |
| 243 EXPECT_CALL(*this, CanPlayThrough()); | |
| 244 SimulateNetwork(1, kMediaByterate / 2, 1000, 20); | |
| 245 | |
| 246 // CanPlayThrough should not be fired because of deferring. | |
| 247 CHECK(!DownloadIsDeferred()); | |
| 163 } | 248 } |
| 164 | 249 |
|
acolwell GONE FROM CHROMIUM
2012/01/09 23:16:57
We should also have some test simulating the Simpl
vrk (LEFT CHROMIUM)
2012/01/11 00:23:13
Both SimpleDataSource and FileDataSource are "loca
| |
| 165 } // namespace media | 250 } // namespace media |
| OLD | NEW |