summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webkit/media/buffered_data_source.cc18
-rw-r--r--webkit/media/buffered_data_source.h12
-rw-r--r--webkit/media/buffered_data_source_unittest.cc216
-rw-r--r--webkit/media/test_response_generator.cc13
-rw-r--r--webkit/media/test_response_generator.h7
5 files changed, 212 insertions, 54 deletions
diff --git a/webkit/media/buffered_data_source.cc b/webkit/media/buffered_data_source.cc
index 7375350..24d9a57 100644
--- a/webkit/media/buffered_data_source.cc
+++ b/webkit/media/buffered_data_source.cc
@@ -40,7 +40,7 @@ BufferedDataSource::BufferedDataSource(
const DownloadingCB& downloading_cb)
: cors_mode_(BufferedResourceLoader::kUnspecified),
total_bytes_(kPositionNotSpecified),
- buffered_bytes_(0),
+ assume_fully_buffered_(false),
streaming_(false),
frame_(frame),
read_size_(0),
@@ -288,7 +288,7 @@ void BufferedDataSource::RestartLoadingTask() {
frame_);
} else {
loader_->Start(
- base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this),
+ base::Bind(&BufferedDataSource::PartialReadStartCallback, this),
base::Bind(&NonHttpLoadingStateChangedCallback),
base::Bind(&NonHttpProgressCallback),
frame_);
@@ -452,7 +452,7 @@ void BufferedDataSource::NonHttpInitialStartCallback(
if (success) {
total_bytes_ = instance_size;
- buffered_bytes_ = total_bytes_;
+ assume_fully_buffered_ = true;
} else {
loader_->Stop();
}
@@ -607,11 +607,13 @@ void BufferedDataSource::UpdateHostState_Locked() {
if (!host())
return;
- if (total_bytes_ != kPositionNotSpecified)
- host()->SetTotalBytes(total_bytes_);
- int64 start = loader_->first_byte_position();
- if (buffered_bytes_ > start)
- host()->AddBufferedByteRange(start, buffered_bytes_);
+ if (total_bytes_ == kPositionNotSpecified)
+ return;
+
+ host()->SetTotalBytes(total_bytes_);
+
+ if (assume_fully_buffered_)
+ host()->AddBufferedByteRange(0, total_bytes_);
}
} // namespace webkit_media
diff --git a/webkit/media/buffered_data_source.h b/webkit/media/buffered_data_source.h
index 61f5e3f..b4526cb 100644
--- a/webkit/media/buffered_data_source.h
+++ b/webkit/media/buffered_data_source.h
@@ -154,12 +154,14 @@ class BufferedDataSource : public media::DataSource {
// crossorigin attribute on the corresponding HTML media element, if any.
BufferedResourceLoader::CORSMode cors_mode_;
- // Members for total bytes of the requested object. It is written once on
- // render thread but may be read from any thread. However reading of this
- // member is guaranteed to happen after it is first written, so we don't
- // need to protect it.
+ // The total size of the resource. Set during StartCallback() if the size is
+ // known, otherwise it will remain kPositionNotSpecified until the size is
+ // determined by reaching EOF.
int64 total_bytes_;
- int64 buffered_bytes_;
+
+ // Some resources are assumed to be fully buffered (i.e., file://) so we don't
+ // need to report what |loader_| has buffered.
+ bool assume_fully_buffered_;
// This value will be true if this data source can only support streaming.
// i.e. range request is not supported.
diff --git a/webkit/media/buffered_data_source_unittest.cc b/webkit/media/buffered_data_source_unittest.cc
index af2a6f7..66059be 100644
--- a/webkit/media/buffered_data_source_unittest.cc
+++ b/webkit/media/buffered_data_source_unittest.cc
@@ -86,11 +86,13 @@ static const int64 kFileSize = 5000000;
static const int64 kFarReadPosition = 4000000;
static const int kDataSize = 1024;
+static const char kHttpUrl[] = "http://localhost/foo.webm";
+static const char kFileUrl[] = "file:///tmp/bar.webm";
+
class BufferedDataSourceTest : public testing::Test {
public:
BufferedDataSourceTest()
- : response_generator_(GURL("http://localhost/foo.webm"), kFileSize),
- view_(WebView::create(NULL)) {
+ : view_(WebView::create(NULL)) {
view_->initializeMainFrame(&client_);
data_source_ = new MockBufferedDataSource(&message_loop_,
@@ -102,23 +104,35 @@ class BufferedDataSourceTest : public testing::Test {
view_->close();
}
- void Initialize(media::PipelineStatus expected) {
- ExpectCreateResourceLoader();
+ void Initialize(const char* url, media::PipelineStatus expected) {
+ GURL gurl(url);
+ response_generator_.reset(new TestResponseGenerator(gurl, kFileSize));
- EXPECT_FALSE(data_source_->downloading());
- data_source_->Initialize(response_generator_.gurl(),
+ ExpectCreateResourceLoader();
+ data_source_->Initialize(gurl,
BufferedResourceLoader::kUnspecified,
media::NewExpectedStatusCB(expected));
message_loop_.RunAllPending();
- EXPECT_TRUE(data_source_->downloading());
+
+ bool is_http = gurl.SchemeIs(kHttpScheme) || gurl.SchemeIs(kHttpsScheme);
+ EXPECT_EQ(data_source_->downloading(), is_http);
}
// Helper to initialize tests with a valid 206 response.
void InitializeWith206Response() {
- Initialize(media::PIPELINE_OK);
+ Initialize(kHttpUrl, media::PIPELINE_OK);
+
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate206(0));
+ }
- EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length()));
- Respond(response_generator_.Generate206(0));
+ // Helper to initialize tests with a valid file:// response.
+ void InitializeWithFileResponse() {
+ Initialize(kFileUrl, media::PIPELINE_OK);
+
+ EXPECT_CALL(host_, SetTotalBytes(kFileSize));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kFileSize));
+ Respond(response_generator_->GenerateFileResponse(0));
}
// Stops any active loaders and shuts down the data source.
@@ -127,7 +141,7 @@ class BufferedDataSourceTest : public testing::Test {
// appropriate to do when tearing down a test.
void Stop() {
if (data_source_->loading()) {
- loader()->didFail(url_loader(), response_generator_.GenerateError());
+ loader()->didFail(url_loader(), response_generator_->GenerateError());
message_loop_.RunAllPending();
}
@@ -189,7 +203,7 @@ class BufferedDataSourceTest : public testing::Test {
scoped_refptr<MockBufferedDataSource> data_source_;
- TestResponseGenerator response_generator_;
+ scoped_ptr<TestResponseGenerator> response_generator_;
MockWebFrameClient client_;
WebView* view_;
@@ -204,10 +218,10 @@ class BufferedDataSourceTest : public testing::Test {
};
TEST_F(BufferedDataSourceTest, Range_Supported) {
- Initialize(media::PIPELINE_OK);
+ Initialize(kHttpUrl, media::PIPELINE_OK);
- EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length()));
- Respond(response_generator_.Generate206(0));
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate206(0));
EXPECT_TRUE(data_source_->loading());
EXPECT_FALSE(data_source_->IsStreaming());
@@ -215,9 +229,9 @@ TEST_F(BufferedDataSourceTest, Range_Supported) {
}
TEST_F(BufferedDataSourceTest, Range_InstanceSizeUnknown) {
- Initialize(media::PIPELINE_OK);
+ Initialize(kHttpUrl, media::PIPELINE_OK);
- Respond(response_generator_.Generate206(
+ Respond(response_generator_->Generate206(
0, TestResponseGenerator::kNoContentRangeInstanceSize));
EXPECT_TRUE(data_source_->loading());
@@ -226,17 +240,17 @@ TEST_F(BufferedDataSourceTest, Range_InstanceSizeUnknown) {
}
TEST_F(BufferedDataSourceTest, Range_NotFound) {
- Initialize(media::PIPELINE_ERROR_NETWORK);
- Respond(response_generator_.Generate404());
+ Initialize(kHttpUrl, media::PIPELINE_ERROR_NETWORK);
+ Respond(response_generator_->Generate404());
EXPECT_FALSE(data_source_->loading());
Stop();
}
TEST_F(BufferedDataSourceTest, Range_NotSupported) {
- Initialize(media::PIPELINE_OK);
- EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length()));
- Respond(response_generator_.Generate200());
+ Initialize(kHttpUrl, media::PIPELINE_OK);
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate200());
EXPECT_TRUE(data_source_->loading());
EXPECT_TRUE(data_source_->IsStreaming());
@@ -246,9 +260,9 @@ TEST_F(BufferedDataSourceTest, Range_NotSupported) {
// Special carve-out for Apache versions that choose to return a 200 for
// Range:0- ("because it's more efficient" than a 206)
TEST_F(BufferedDataSourceTest, Range_SupportedButReturned200) {
- Initialize(media::PIPELINE_OK);
- EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length()));
- WebURLResponse response = response_generator_.Generate200();
+ Initialize(kHttpUrl, media::PIPELINE_OK);
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ WebURLResponse response = response_generator_->Generate200();
response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"),
WebString::fromUTF8("bytes"));
Respond(response);
@@ -259,8 +273,8 @@ TEST_F(BufferedDataSourceTest, Range_SupportedButReturned200) {
}
TEST_F(BufferedDataSourceTest, Range_MissingContentRange) {
- Initialize(media::PIPELINE_ERROR_NETWORK);
- Respond(response_generator_.Generate206(
+ Initialize(kHttpUrl, media::PIPELINE_ERROR_NETWORK);
+ Respond(response_generator_->Generate206(
0, TestResponseGenerator::kNoContentRange));
EXPECT_FALSE(data_source_->loading());
@@ -268,11 +282,11 @@ TEST_F(BufferedDataSourceTest, Range_MissingContentRange) {
}
TEST_F(BufferedDataSourceTest, Range_MissingContentLength) {
- Initialize(media::PIPELINE_OK);
+ Initialize(kHttpUrl, media::PIPELINE_OK);
// It'll manage without a Content-Length response.
- EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length()));
- Respond(response_generator_.Generate206(
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate206(
0, TestResponseGenerator::kNoContentLength));
EXPECT_TRUE(data_source_->loading());
@@ -281,10 +295,10 @@ TEST_F(BufferedDataSourceTest, Range_MissingContentLength) {
}
TEST_F(BufferedDataSourceTest, Range_WrongContentRange) {
- Initialize(media::PIPELINE_ERROR_NETWORK);
+ Initialize(kHttpUrl, media::PIPELINE_ERROR_NETWORK);
// Now it's done and will fail.
- Respond(response_generator_.Generate206(1337));
+ Respond(response_generator_->Generate206(1337));
EXPECT_FALSE(data_source_->loading());
Stop();
@@ -301,13 +315,13 @@ TEST_F(BufferedDataSourceTest, Range_ServerLied) {
// Return a 200 in response to a range request.
EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
- Respond(response_generator_.Generate200());
+ Respond(response_generator_->Generate200());
EXPECT_FALSE(data_source_->loading());
Stop();
}
-TEST_F(BufferedDataSourceTest, Range_AbortWhileReading) {
+TEST_F(BufferedDataSourceTest, Http_AbortWhileReading) {
InitializeWith206Response();
// Make sure there's a pending read -- we'll expect it to error.
@@ -322,7 +336,68 @@ TEST_F(BufferedDataSourceTest, Range_AbortWhileReading) {
Stop();
}
-TEST_F(BufferedDataSourceTest, Range_TooManyRetries) {
+TEST_F(BufferedDataSourceTest, File_AbortWhileReading) {
+ InitializeWithFileResponse();
+
+ // Make sure there's a pending read -- we'll expect it to error.
+ ReadAt(0);
+
+ // Abort!!!
+ EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
+ data_source_->Abort();
+ message_loop_.RunAllPending();
+
+ EXPECT_FALSE(data_source_->loading());
+ Stop();
+}
+
+TEST_F(BufferedDataSourceTest, Http_Retry) {
+ InitializeWith206Response();
+
+ // Read to advance our position.
+ EXPECT_CALL(*this, ReadCallback(kDataSize));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize - 1));
+ ReadAt(0);
+ ReceiveData(kDataSize);
+
+ // Issue a pending read but terminate the connection to force a retry.
+ ReadAt(kDataSize);
+ ExpectCreateResourceLoader();
+ FinishLoading();
+ Respond(response_generator_->Generate206(kDataSize));
+
+ // Complete the read.
+ EXPECT_CALL(*this, ReadCallback(kDataSize));
+ EXPECT_CALL(host_, AddBufferedByteRange(kDataSize, (kDataSize * 2) - 1));
+ ReceiveData(kDataSize);
+
+ EXPECT_TRUE(data_source_->loading());
+ Stop();
+}
+
+TEST_F(BufferedDataSourceTest, File_Retry) {
+ InitializeWithFileResponse();
+
+ // Read to advance our position.
+ EXPECT_CALL(*this, ReadCallback(kDataSize));
+ ReadAt(0);
+ ReceiveData(kDataSize);
+
+ // Issue a pending read but terminate the connection to force a retry.
+ ReadAt(kDataSize);
+ ExpectCreateResourceLoader();
+ FinishLoading();
+ Respond(response_generator_->GenerateFileResponse(kDataSize));
+
+ // Complete the read.
+ EXPECT_CALL(*this, ReadCallback(kDataSize));
+ ReceiveData(kDataSize);
+
+ EXPECT_TRUE(data_source_->loading());
+ Stop();
+}
+
+TEST_F(BufferedDataSourceTest, Http_TooManyRetries) {
InitializeWith206Response();
// Make sure there's a pending read -- we'll expect it to error.
@@ -331,15 +406,42 @@ TEST_F(BufferedDataSourceTest, Range_TooManyRetries) {
// It'll try three times.
ExpectCreateResourceLoader();
FinishLoading();
- Respond(response_generator_.Generate206(0));
+ Respond(response_generator_->Generate206(0));
+
+ ExpectCreateResourceLoader();
+ FinishLoading();
+ Respond(response_generator_->Generate206(0));
+
+ ExpectCreateResourceLoader();
+ FinishLoading();
+ Respond(response_generator_->Generate206(0));
+
+ // It'll error after this.
+ EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
+ FinishLoading();
+
+ EXPECT_FALSE(data_source_->loading());
+ Stop();
+}
+
+TEST_F(BufferedDataSourceTest, File_TooManyRetries) {
+ InitializeWithFileResponse();
+
+ // Make sure there's a pending read -- we'll expect it to error.
+ ReadAt(0);
+
+ // It'll try three times.
+ ExpectCreateResourceLoader();
+ FinishLoading();
+ Respond(response_generator_->GenerateFileResponse(0));
ExpectCreateResourceLoader();
FinishLoading();
- Respond(response_generator_.Generate206(0));
+ Respond(response_generator_->GenerateFileResponse(0));
ExpectCreateResourceLoader();
FinishLoading();
- Respond(response_generator_.Generate206(0));
+ Respond(response_generator_->GenerateFileResponse(0));
// It'll error after this.
EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
@@ -349,6 +451,23 @@ TEST_F(BufferedDataSourceTest, Range_TooManyRetries) {
Stop();
}
+TEST_F(BufferedDataSourceTest, File_InstanceSizeUnknown) {
+ Initialize(kFileUrl, media::PIPELINE_ERROR_NETWORK);
+ EXPECT_FALSE(data_source_->downloading());
+
+ Respond(response_generator_->GenerateFileResponse(-1));
+
+ EXPECT_FALSE(data_source_->loading());
+ Stop();
+}
+
+TEST_F(BufferedDataSourceTest, File_Successful) {
+ InitializeWithFileResponse();
+
+ EXPECT_TRUE(data_source_->loading());
+ Stop();
+}
+
static void SetTrue(bool* value) {
*value = true;
}
@@ -402,7 +521,7 @@ TEST_F(BufferedDataSourceTest, SetBitrate) {
BufferedResourceLoader* old_loader = loader();
ExpectCreateResourceLoader();
ReadAt(kFarReadPosition);
- Respond(response_generator_.Generate206(kFarReadPosition));
+ Respond(response_generator_->Generate206(kFarReadPosition));
// Verify loader changed but still has same bitrate.
EXPECT_NE(old_loader, loader());
@@ -425,7 +544,7 @@ TEST_F(BufferedDataSourceTest, SetPlaybackRate) {
BufferedResourceLoader* old_loader = loader();
ExpectCreateResourceLoader();
ReadAt(kFarReadPosition);
- Respond(response_generator_.Generate206(kFarReadPosition));
+ Respond(response_generator_->Generate206(kFarReadPosition));
// Verify loader changed but still has same playback rate.
EXPECT_NE(old_loader, loader());
@@ -435,7 +554,7 @@ TEST_F(BufferedDataSourceTest, SetPlaybackRate) {
Stop();
}
-TEST_F(BufferedDataSourceTest, Read) {
+TEST_F(BufferedDataSourceTest, Http_Read) {
InitializeWith206Response();
ReadAt(0);
@@ -453,4 +572,19 @@ TEST_F(BufferedDataSourceTest, Read) {
Stop();
}
+TEST_F(BufferedDataSourceTest, File_Read) {
+ InitializeWithFileResponse();
+
+ ReadAt(0);
+
+ // Receive first half of the read but no buffering update.
+ ReceiveData(kDataSize / 2);
+
+ // Receive last half of the read but no buffering update.
+ EXPECT_CALL(*this, ReadCallback(kDataSize));
+ ReceiveData(kDataSize / 2);
+
+ Stop();
+}
+
} // namespace webkit_media
diff --git a/webkit/media/test_response_generator.cc b/webkit/media/test_response_generator.cc
index d5485b3..b2d605c 100644
--- a/webkit/media/test_response_generator.cc
+++ b/webkit/media/test_response_generator.cc
@@ -85,4 +85,17 @@ WebURLResponse TestResponseGenerator::Generate404() {
return response;
}
+WebURLResponse TestResponseGenerator::GenerateFileResponse(
+ int64 first_byte_offset) {
+ WebURLResponse response(gurl_);
+ response.setHTTPStatusCode(0);
+
+ if (first_byte_offset >= 0) {
+ response.setExpectedContentLength(content_length_ - first_byte_offset);
+ } else {
+ response.setExpectedContentLength(-1);
+ }
+ return response;
+}
+
} // namespace webkit_media
diff --git a/webkit/media/test_response_generator.h b/webkit/media/test_response_generator.h
index d912d88..f73e94b 100644
--- a/webkit/media/test_response_generator.h
+++ b/webkit/media/test_response_generator.h
@@ -45,6 +45,13 @@ class TestResponseGenerator {
// Generates a regular HTTP 404 response.
WebKit::WebURLResponse Generate404();
+ // Generates a file:// response starting from |first_byte_offset| until the
+ // end of the resource.
+ //
+ // If |first_byte_offset| is negative a response containing no content length
+ // will be returned.
+ WebKit::WebURLResponse GenerateFileResponse(int64 first_byte_offset);
+
const GURL& gurl() { return gurl_; }
int64 content_length() { return content_length_; }