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 } | 20 base::Unretained(this))) { } |
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 kMediaSizeInBytes = 20 * 1024 * 1024; | 27 static const int kMediaDuration = 120; |
28 | 28 static const int kMediaBitrate = 1024 * 1024 * 8; |
29 // Simulates downloading of the media file. Packets are timed evenly in | 29 static const int kMediaByterate = kMediaBitrate / 8; |
30 // |ms_between_packets| intervals, starting at |starting_time|, which is | 30 static const int kMediaSizeInBytes = kMediaDuration * kMediaByterate; |
31 // number of seconds since unix epoch (Jan 1, 1970). | 31 static const int kDeferThreshold = 30 * kMediaByterate; |
32 // Returns the number of bytes buffered in the media file after the | 32 |
33 // network activity. | 33 // Simulates downloading |bytes_to_download| bytes of the media file, at |
34 int SimulateNetwork(double starting_time, | 34 // |download_speed_in_bps| bytes per second. |
35 int starting_bytes, | 35 void SimulateNetwork(int bytes_to_download, int download_speed_in_bps) { |
36 int bytes_per_packet, | 36 int bytes_downloaded = 0; |
37 int ms_between_packets, | 37 while (bytes_downloaded < bytes_to_download && |
38 int number_of_packets) { | 38 !data_source_.is_deferred()) { |
39 int bytes_buffered = starting_bytes; | 39 int bytes_left_to_download = bytes_to_download - bytes_downloaded; |
40 base::Time packet_time = base::Time::FromDoubleT(starting_time); | 40 int packet_size = std::min(download_speed_in_bps, bytes_left_to_download); |
41 | 41 time_elapsed_ += base::TimeDelta::FromMilliseconds( |
42 monitor_.SetNetworkActivity(true); | 42 1000 * packet_size / download_speed_in_bps); |
43 // Loop executes (number_of_packets + 1) times because a packet needs a | 43 data_source_.ReceiveData( |
44 // starting and end point. | 44 packet_size, time_elapsed_ + base::Time::UnixEpoch()); |
45 for (int i = 0; i < number_of_packets + 1; ++i) { | 45 bytes_downloaded += packet_size; |
46 monitor_.SetBufferedBytes(bytes_buffered, packet_time); | 46 } |
47 packet_time += base::TimeDelta::FromMilliseconds(ms_between_packets); | 47 } |
48 bytes_buffered += bytes_per_packet; | 48 |
49 } | 49 void Initialize() { |
50 monitor_.SetNetworkActivity(false); | 50 Initialize(false, false); |
51 return bytes_buffered; | 51 } |
52 } | 52 |
53 | 53 void Initialize(bool streaming, bool local_source) { |
54 void StartMonitor(int bitrate) { | 54 data_source_.Initialize( |
55 StartMonitor(bitrate, false, false); | 55 kMediaBitrate, streaming, local_source, canplaythrough_cb_); |
56 } | 56 } |
57 | 57 |
58 void StartMonitor(int bitrate, bool streaming, bool local_source) { | 58 bool DownloadIsDeferred() { |
59 monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, | 59 return data_source_.is_deferred(); |
60 base::Unretained(this)), bitrate, streaming, local_source); | 60 } |
61 } | 61 |
62 | 62 void SeekTo(int offset) { |
63 DownloadRateMonitor monitor_; | 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 } |
64 | 70 |
65 private: | 71 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 |
66 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); | 134 DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest); |
67 }; | 135 }; |
68 | 136 |
69 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { | 137 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { |
70 static const int media_bitrate = 1024 * 1024 * 8; | |
71 | |
72 // Simulate downloading at double the media's bitrate. | 138 // Simulate downloading at double the media's bitrate. |
73 StartMonitor(media_bitrate); | 139 Initialize(); |
74 EXPECT_CALL(*this, CanPlayThrough()); | 140 EXPECT_CALL(*this, CanPlayThrough()); |
75 SimulateNetwork(1, 0, 2 * media_bitrate / 8, 1000, 10); | 141 SimulateNetwork(SecondsToBytes(20), 2 * kMediaByterate); |
76 } | 142 } |
77 | 143 |
78 // If the user pauses and the pipeline stops downloading data, make sure the | 144 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate_Defer) { |
79 // DownloadRateMonitor understands that the download is not stalling. | 145 Initialize(); |
80 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_Pause) { | 146 |
81 static const int media_bitrate = 1024 * 1024 * 8; | 147 // 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; | 148 // the data source defers. |
83 | 149 EXPECT_CALL(*this, CanPlayThrough()); |
| 150 SimulateNetwork(kDeferThreshold, 0.3 * kMediaByterate); |
| 151 CHECK(DownloadIsDeferred()); |
| 152 } |
| 153 |
| 154 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) { |
84 // Start downloading faster than the media's bitrate. | 155 // Start downloading faster than the media's bitrate. |
85 StartMonitor(media_bitrate); | 156 Initialize(); |
86 EXPECT_CALL(*this, CanPlayThrough()); | 157 SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate); |
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 | 158 |
102 // Then seek forward mid-file and continue downloading at same rate. | 159 // Then seek forward mid-file and continue downloading at same rate. |
103 SimulateNetwork(4, kMediaSizeInBytes / 2, download_byte_rate, 1000, 4); | 160 SeekTo(kMediaSizeInBytes / 2); |
| 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()); |
104 } | 166 } |
105 | 167 |
106 TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) { | 168 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. | 169 // Start downloading faster than the media's bitrate, in middle of file. |
111 StartMonitor(media_bitrate); | 170 Initialize(); |
112 SimulateNetwork(1, kMediaSizeInBytes / 2, download_byte_rate, 1000, 2); | 171 SeekTo(kMediaSizeInBytes / 2); |
| 172 SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate); |
113 | 173 |
114 // Then seek back to beginning and continue downloading at same rate. | 174 // Then seek back to beginning and continue downloading at same rate. |
115 EXPECT_CALL(*this, CanPlayThrough()); | 175 SeekTo(0); |
116 SimulateNetwork(4, 0, download_byte_rate, 1000, 4); | 176 EXPECT_CALL(*this, CanPlayThrough()); |
117 } | 177 SimulateNetwork(SecondsToBytes(7), 1.1 * kMediaByterate); |
118 | 178 |
119 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) { | 179 // Verify deferring is not what caused CanPlayThrough to fire. |
120 static const int media_bitrate = 1024 * 1024 * 8; | 180 CHECK(!DownloadIsDeferred()); |
121 | 181 } |
| 182 |
| 183 TEST_F(DownloadRateMonitorTest, DownloadRateLessThanByterate) { |
122 // Simulate downloading at half the media's bitrate. | 184 // Simulate downloading at half the media's bitrate. |
123 EXPECT_CALL(*this, CanPlayThrough()) | 185 EXPECT_CALL(*this, CanPlayThrough()) |
124 .Times(0); | 186 .Times(0); |
125 StartMonitor(media_bitrate); | 187 Initialize(); |
126 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, 10); | 188 SimulateNetwork(SecondsToBytes(10), kMediaByterate / 2); |
127 } | 189 } |
128 | 190 |
129 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { | 191 TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { |
130 static const int media_bitrate = 1024 * 1024 * 8; | |
131 | |
132 // Simulate no data downloaded. | 192 // Simulate no data downloaded. |
133 EXPECT_CALL(*this, CanPlayThrough()); | 193 EXPECT_CALL(*this, CanPlayThrough()); |
134 StartMonitor(media_bitrate, false, true); | 194 Initialize(false, true); |
135 } | 195 } |
136 | 196 |
137 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { | 197 TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { |
138 static const int media_bitrate = 1024 * 1024 * 8; | |
139 | |
140 // Simulate downloading at the media's bitrate while streaming. | 198 // Simulate downloading at the media's bitrate while streaming. |
141 EXPECT_CALL(*this, CanPlayThrough()); | 199 EXPECT_CALL(*this, CanPlayThrough()); |
142 StartMonitor(media_bitrate, true, false); | 200 Initialize(true, false); |
143 SimulateNetwork(1, 0, media_bitrate / 8, 1000, 10); | 201 SimulateNetwork(SecondsToBytes(10), kMediaByterate); |
144 } | 202 } |
145 | 203 |
146 TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { | 204 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. | 205 // Simulate downloading half the video very quickly in one chunk. |
150 StartMonitor(media_bitrate); | 206 Initialize(); |
151 EXPECT_CALL(*this, CanPlayThrough()); | 207 EXPECT_CALL(*this, CanPlayThrough()); |
152 SimulateNetwork(1, 0, kMediaSizeInBytes / 2, 10, 1); | 208 SimulateNetwork(kMediaSizeInBytes / 2, kMediaSizeInBytes * 10); |
153 } | 209 } |
154 | 210 |
155 TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { | 211 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. | 212 // Simulate downloading entire video at half the bitrate of the video. |
160 StartMonitor(media_bitrate); | 213 Initialize(); |
161 EXPECT_CALL(*this, CanPlayThrough()); | 214 EXPECT_CALL(*this, CanPlayThrough()); |
162 SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, seconds_of_data * 2); | 215 SimulateNetwork(kMediaSizeInBytes, kMediaByterate / 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()); |
163 } | 228 } |
164 | 229 |
165 } // namespace media | 230 } // namespace media |
OLD | NEW |