mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add Downloader for progressive content
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162348129
This commit is contained in:
parent
0717c3502f
commit
e26b8824dd
2 changed files with 101 additions and 132 deletions
|
|
@ -42,6 +42,7 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
* create a proxy for it.
|
* create a proxy for it.
|
||||||
*/
|
*/
|
||||||
public abstract static class AbstractFakeCache implements Cache {
|
public abstract static class AbstractFakeCache implements Cache {
|
||||||
|
|
||||||
// This array is set to alternating length of cached and not cached regions in tests:
|
// This array is set to alternating length of cached and not cached regions in tests:
|
||||||
// spansAndGaps = {<length of 1st cached region>, <length of 1st not cached region>,
|
// spansAndGaps = {<length of 1st cached region>, <length of 1st not cached region>,
|
||||||
// <length of 2nd cached region>, <length of 2nd not cached region>, ... }
|
// <length of 2nd cached region>, <length of 2nd not cached region>, ... }
|
||||||
|
|
@ -50,7 +51,7 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
private long contentLength;
|
private long contentLength;
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
spansAndGaps = new int[]{};
|
spansAndGaps = new int[] {};
|
||||||
contentLength = C.LENGTH_UNSET;
|
contentLength = C.LENGTH_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,46 +117,35 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
CacheUtil.getKey(new DataSpec(testUri, 0, C.LENGTH_UNSET, null)));
|
CacheUtil.getKey(new DataSpec(testUri, 0, C.LENGTH_UNSET, null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetCachedCachingCounters() throws Exception {
|
|
||||||
DataSpec dataSpec = new DataSpec(Uri.parse("test"));
|
|
||||||
CachingCounters counters = CacheUtil.getCached(dataSpec, mockCache, null);
|
|
||||||
// getCached should create a CachingCounters and return it
|
|
||||||
assertNotNull(counters);
|
|
||||||
|
|
||||||
CachingCounters newCounters = CacheUtil.getCached(dataSpec, mockCache, counters);
|
|
||||||
// getCached should set and return given CachingCounters
|
|
||||||
assertEquals(counters, newCounters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetCachedNoData() throws Exception {
|
public void testGetCachedNoData() throws Exception {
|
||||||
CachingCounters counters =
|
CachingCounters counters = new CachingCounters();
|
||||||
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null);
|
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 0, C.LENGTH_UNSET);
|
assertCounters(counters, 0, 0, C.LENGTH_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetCachedDataUnknownLength() throws Exception {
|
public void testGetCachedDataUnknownLength() throws Exception {
|
||||||
// Mock there is 100 bytes cached at the beginning
|
// Mock there is 100 bytes cached at the beginning
|
||||||
mockCache.spansAndGaps = new int[]{100};
|
mockCache.spansAndGaps = new int[] {100};
|
||||||
CachingCounters counters =
|
CachingCounters counters = new CachingCounters();
|
||||||
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null);
|
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters);
|
||||||
|
|
||||||
assertCounters(counters, 100, 0, C.LENGTH_UNSET);
|
assertCounters(counters, 100, 0, C.LENGTH_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetCachedNoDataKnownLength() throws Exception {
|
public void testGetCachedNoDataKnownLength() throws Exception {
|
||||||
mockCache.contentLength = 1000;
|
mockCache.contentLength = 1000;
|
||||||
CachingCounters counters =
|
CachingCounters counters = new CachingCounters();
|
||||||
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null);
|
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 0, 1000);
|
assertCounters(counters, 0, 0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetCached() throws Exception {
|
public void testGetCached() throws Exception {
|
||||||
mockCache.contentLength = 1000;
|
mockCache.contentLength = 1000;
|
||||||
mockCache.spansAndGaps = new int[]{100, 100, 200};
|
mockCache.spansAndGaps = new int[] {100, 100, 200};
|
||||||
CachingCounters counters =
|
CachingCounters counters = new CachingCounters();
|
||||||
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null);
|
CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters);
|
||||||
|
|
||||||
assertCounters(counters, 300, 0, 1000);
|
assertCounters(counters, 300, 0, 1000);
|
||||||
}
|
}
|
||||||
|
|
@ -164,8 +154,8 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
|
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
|
||||||
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
|
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
|
||||||
|
|
||||||
CachingCounters counters =
|
CachingCounters counters = new CachingCounters();
|
||||||
CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, null);
|
CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 100, 100);
|
assertCounters(counters, 0, 100, 100);
|
||||||
assertCachedData(cache, fakeDataSet);
|
assertCachedData(cache, fakeDataSet);
|
||||||
|
|
@ -177,7 +167,8 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
Uri testUri = Uri.parse("test_data");
|
Uri testUri = Uri.parse("test_data");
|
||||||
DataSpec dataSpec = new DataSpec(testUri, 10, 20, null);
|
DataSpec dataSpec = new DataSpec(testUri, 10, 20, null);
|
||||||
CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null);
|
CachingCounters counters = new CachingCounters();
|
||||||
|
CacheUtil.cache(dataSpec, cache, dataSource, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 20, 20);
|
assertCounters(counters, 0, 20, 20);
|
||||||
|
|
||||||
|
|
@ -194,7 +185,8 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
|
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
|
||||||
|
|
||||||
DataSpec dataSpec = new DataSpec(Uri.parse("test_data"));
|
DataSpec dataSpec = new DataSpec(Uri.parse("test_data"));
|
||||||
CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null);
|
CachingCounters counters = new CachingCounters();
|
||||||
|
CacheUtil.cache(dataSpec, cache, dataSource, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 100, 100);
|
assertCounters(counters, 0, 100, 100);
|
||||||
assertCachedData(cache, fakeDataSet);
|
assertCachedData(cache, fakeDataSet);
|
||||||
|
|
@ -208,7 +200,8 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
Uri testUri = Uri.parse("test_data");
|
Uri testUri = Uri.parse("test_data");
|
||||||
DataSpec dataSpec = new DataSpec(testUri, 10, 20, null);
|
DataSpec dataSpec = new DataSpec(testUri, 10, 20, null);
|
||||||
CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null);
|
CachingCounters counters = new CachingCounters();
|
||||||
|
CacheUtil.cache(dataSpec, cache, dataSource, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 20, 20);
|
assertCounters(counters, 0, 20, 20);
|
||||||
|
|
||||||
|
|
@ -224,7 +217,8 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
Uri testUri = Uri.parse("test_data");
|
Uri testUri = Uri.parse("test_data");
|
||||||
DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null);
|
DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null);
|
||||||
CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null);
|
CachingCounters counters = new CachingCounters();
|
||||||
|
CacheUtil.cache(dataSpec, cache, dataSource, counters);
|
||||||
|
|
||||||
assertCounters(counters, 0, 100, 1000);
|
assertCounters(counters, 0, 100, 1000);
|
||||||
assertCachedData(cache, fakeDataSet);
|
assertCachedData(cache, fakeDataSet);
|
||||||
|
|
@ -288,10 +282,10 @@ public class CacheUtilTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertCounters(CachingCounters counters, int alreadyCachedBytes,
|
private static void assertCounters(CachingCounters counters, int alreadyCachedBytes,
|
||||||
int downloadedBytes, int totalBytes) {
|
int newlyCachedBytes, int contentLength) {
|
||||||
assertEquals(alreadyCachedBytes, counters.alreadyCachedBytes);
|
assertEquals(alreadyCachedBytes, counters.alreadyCachedBytes);
|
||||||
assertEquals(downloadedBytes, counters.downloadedBytes);
|
assertEquals(newlyCachedBytes, counters.newlyCachedBytes);
|
||||||
assertEquals(totalBytes, counters.totalBytes);
|
assertEquals(contentLength, counters.contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 The Android Open Source Project
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.upstream.cache;
|
package com.google.android.exoplayer2.upstream.cache;
|
||||||
|
|
@ -32,17 +32,21 @@ import java.util.NavigableSet;
|
||||||
@SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"})
|
@SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"})
|
||||||
public final class CacheUtil {
|
public final class CacheUtil {
|
||||||
|
|
||||||
/** Holds the counters used during caching. */
|
/** Counters used during caching. */
|
||||||
public static class CachingCounters {
|
public static class CachingCounters {
|
||||||
/** Total number of already cached bytes. */
|
/** The number of bytes already in the cache. */
|
||||||
public volatile long alreadyCachedBytes;
|
public volatile long alreadyCachedBytes;
|
||||||
/** Total number of downloaded bytes. */
|
/** The number of newly cached bytes. */
|
||||||
public volatile long downloadedBytes;
|
public volatile long newlyCachedBytes;
|
||||||
|
/** The length of the content being cached in bytes, or {@link C#LENGTH_UNSET} if unknown. */
|
||||||
|
public volatile long contentLength = C.LENGTH_UNSET;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total number of bytes. This is the sum of already cached, downloaded and missing bytes. If
|
* Returns the sum of {@link #alreadyCachedBytes} and {@link #newlyCachedBytes}.
|
||||||
* the length of the missing bytes is unknown this is set to {@link C#LENGTH_UNSET}.
|
|
||||||
*/
|
*/
|
||||||
public volatile long totalBytes = C.LENGTH_UNSET;
|
public long totalCachedBytes() {
|
||||||
|
return alreadyCachedBytes + newlyCachedBytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default buffer size to be used while caching. */
|
/** Default buffer size to be used while caching. */
|
||||||
|
|
@ -68,40 +72,51 @@ public final class CacheUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns already cached and missing bytes in the {@code cache} for the data defined by {@code
|
* Sets a {@link CachingCounters} to contain the number of bytes already downloaded and the
|
||||||
* dataSpec}.
|
* length for the content defined by a {@code dataSpec}. {@link CachingCounters#newlyCachedBytes}
|
||||||
|
* is reset to 0.
|
||||||
*
|
*
|
||||||
* @param dataSpec Defines the data to be checked.
|
* @param dataSpec Defines the data to be checked.
|
||||||
* @param cache A {@link Cache} which has the data.
|
* @param cache A {@link Cache} which has the data.
|
||||||
* @param counters The counters to be set. If null a new {@link CachingCounters} is created and
|
* @param counters The {@link CachingCounters} to update.
|
||||||
* used.
|
|
||||||
* @return The used {@link CachingCounters} instance.
|
|
||||||
*/
|
*/
|
||||||
public static CachingCounters getCached(DataSpec dataSpec, Cache cache,
|
public static void getCached(DataSpec dataSpec, Cache cache, CachingCounters counters) {
|
||||||
CachingCounters counters) {
|
String key = getKey(dataSpec);
|
||||||
try {
|
long start = dataSpec.absoluteStreamPosition;
|
||||||
return internalCache(dataSpec, cache, null, null, null, 0, counters, false);
|
long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key);
|
||||||
} catch (IOException | InterruptedException e) {
|
counters.contentLength = left;
|
||||||
throw new IllegalStateException(e);
|
counters.alreadyCachedBytes = 0;
|
||||||
|
counters.newlyCachedBytes = 0;
|
||||||
|
while (left != 0) {
|
||||||
|
long blockLength = cache.getCachedBytes(key, start,
|
||||||
|
left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||||
|
if (blockLength > 0) {
|
||||||
|
counters.alreadyCachedBytes += blockLength;
|
||||||
|
} else {
|
||||||
|
blockLength = -blockLength;
|
||||||
|
if (blockLength == Long.MAX_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start += blockLength;
|
||||||
|
left -= left == C.LENGTH_UNSET ? 0 : blockLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches the data defined by {@code dataSpec} while skipping already cached data. Caching stops
|
* Caches the data defined by {@code dataSpec}, skipping already cached data. Caching stops early
|
||||||
* early if end of input is reached.
|
* if the end of the input is reached.
|
||||||
*
|
*
|
||||||
* @param dataSpec Defines the data to be cached.
|
* @param dataSpec Defines the data to be cached.
|
||||||
* @param cache A {@link Cache} to store the data.
|
* @param cache A {@link Cache} to store the data.
|
||||||
* @param upstream A {@link DataSource} for reading data not in the cache.
|
* @param upstream A {@link DataSource} for reading data not in the cache.
|
||||||
* @param counters The counters to be set during caching. If not null its values reset to
|
* @param counters Counters to update during caching.
|
||||||
* zero before using. If null a new {@link CachingCounters} is created and used.
|
|
||||||
* @return The used {@link CachingCounters} instance.
|
|
||||||
* @throws IOException If an error occurs reading from the source.
|
* @throws IOException If an error occurs reading from the source.
|
||||||
* @throws InterruptedException If the thread was interrupted.
|
* @throws InterruptedException If the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public static CachingCounters cache(DataSpec dataSpec, Cache cache,
|
public static void cache(DataSpec dataSpec, Cache cache, DataSource upstream,
|
||||||
DataSource upstream, CachingCounters counters) throws IOException, InterruptedException {
|
CachingCounters counters) throws IOException, InterruptedException {
|
||||||
return cache(dataSpec, cache, new CacheDataSource(cache, upstream),
|
cache(dataSpec, cache, new CacheDataSource(cache, upstream),
|
||||||
new byte[DEFAULT_BUFFER_SIZE_BYTES], null, 0, counters, false);
|
new byte[DEFAULT_BUFFER_SIZE_BYTES], null, 0, counters, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,91 +131,51 @@ public final class CacheUtil {
|
||||||
* @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with
|
* @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with
|
||||||
* caching.
|
* caching.
|
||||||
* @param priority The priority of this task. Used with {@code priorityTaskManager}.
|
* @param priority The priority of this task. Used with {@code priorityTaskManager}.
|
||||||
* @param counters The counters to be set during caching. If not null its values reset to
|
* @param counters Counters to update during caching.
|
||||||
* zero before using. If null a new {@link CachingCounters} is created and used.
|
|
||||||
* @param enableEOFException Whether to throw an {@link EOFException} if end of input has been
|
* @param enableEOFException Whether to throw an {@link EOFException} if end of input has been
|
||||||
* reached unexpectedly.
|
* reached unexpectedly.
|
||||||
* @return The used {@link CachingCounters} instance.
|
|
||||||
* @throws IOException If an error occurs reading from the source.
|
* @throws IOException If an error occurs reading from the source.
|
||||||
* @throws InterruptedException If the thread was interrupted.
|
* @throws InterruptedException If the thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public static CachingCounters cache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource,
|
public static void cache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource,
|
||||||
byte[] buffer, PriorityTaskManager priorityTaskManager, int priority,
|
byte[] buffer, PriorityTaskManager priorityTaskManager, int priority,
|
||||||
CachingCounters counters, boolean enableEOFException)
|
CachingCounters counters, boolean enableEOFException)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
Assertions.checkNotNull(dataSource);
|
Assertions.checkNotNull(dataSource);
|
||||||
Assertions.checkNotNull(buffer);
|
Assertions.checkNotNull(buffer);
|
||||||
return internalCache(dataSpec, cache, dataSource, buffer, priorityTaskManager, priority,
|
|
||||||
counters, enableEOFException);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (counters != null) {
|
||||||
* Caches the data defined by {@code dataSpec} while skipping already cached data. If {@code
|
// Initialize the CachingCounter values.
|
||||||
* dataSource} or {@code buffer} is null performs a dry run.
|
getCached(dataSpec, cache, counters);
|
||||||
*
|
|
||||||
* @param dataSpec Defines the data to be cached.
|
|
||||||
* @param cache A {@link Cache} to store the data.
|
|
||||||
* @param dataSource A {@link CacheDataSource} that works on the {@code cache}. If null a dry run
|
|
||||||
* is performed.
|
|
||||||
* @param buffer The buffer to be used while caching. If null a dry run is performed.
|
|
||||||
* @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with
|
|
||||||
* caching.
|
|
||||||
* @param priority The priority of this task. Used with {@code priorityTaskManager}.
|
|
||||||
* @param counters The counters to be set during caching. If not null its values reset to
|
|
||||||
* zero before using. If null a new {@link CachingCounters} is created and used.
|
|
||||||
* @param enableEOFException Whether to throw an {@link EOFException} if end of input has been
|
|
||||||
* reached unexpectedly.
|
|
||||||
* @return The used {@link CachingCounters} instance.
|
|
||||||
* @throws IOException If not dry run and an error occurs reading from the source.
|
|
||||||
* @throws InterruptedException If not dry run and the thread was interrupted.
|
|
||||||
*/
|
|
||||||
private static CachingCounters internalCache(DataSpec dataSpec, Cache cache,
|
|
||||||
CacheDataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager,
|
|
||||||
int priority, CachingCounters counters, boolean enableEOFException)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
long start = dataSpec.absoluteStreamPosition;
|
|
||||||
long left = dataSpec.length;
|
|
||||||
String key = getKey(dataSpec);
|
|
||||||
if (left == C.LENGTH_UNSET) {
|
|
||||||
left = cache.getContentLength(key);
|
|
||||||
}
|
|
||||||
if (counters == null) {
|
|
||||||
counters = new CachingCounters();
|
|
||||||
} else {
|
} else {
|
||||||
counters.alreadyCachedBytes = 0;
|
// Dummy CachingCounters. No need to initialize as they will not be visible to the caller.
|
||||||
counters.downloadedBytes = 0;
|
counters = new CachingCounters();
|
||||||
}
|
}
|
||||||
counters.totalBytes = left;
|
|
||||||
|
|
||||||
|
String key = getKey(dataSpec);
|
||||||
|
long start = dataSpec.absoluteStreamPosition;
|
||||||
|
long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key);
|
||||||
while (left != 0) {
|
while (left != 0) {
|
||||||
long blockLength = cache.getCachedBytes(key, start,
|
long blockLength = cache.getCachedBytes(key, start,
|
||||||
left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||||
// Skip already cached data
|
|
||||||
if (blockLength > 0) {
|
if (blockLength > 0) {
|
||||||
counters.alreadyCachedBytes += blockLength;
|
// Skip already cached data.
|
||||||
} else {
|
} else {
|
||||||
// There is a hole in the cache which is at least "-blockLength" long.
|
// There is a hole in the cache which is at least "-blockLength" long.
|
||||||
blockLength = -blockLength;
|
blockLength = -blockLength;
|
||||||
if (dataSource != null && buffer != null) {
|
long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer,
|
||||||
long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer,
|
priorityTaskManager, priority, counters);
|
||||||
priorityTaskManager, priority, counters);
|
if (read < blockLength) {
|
||||||
if (read < blockLength) {
|
// Reached to the end of the data.
|
||||||
// Reached to the end of the data.
|
if (enableEOFException && left != C.LENGTH_UNSET) {
|
||||||
if (enableEOFException && left != C.LENGTH_UNSET) {
|
throw new EOFException();
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else if (blockLength == Long.MAX_VALUE) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
start += blockLength;
|
start += blockLength;
|
||||||
if (left != C.LENGTH_UNSET) {
|
left -= left == C.LENGTH_UNSET ? 0 : blockLength;
|
||||||
left -= blockLength;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return counters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -215,7 +190,7 @@ public final class CacheUtil {
|
||||||
* @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with
|
* @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with
|
||||||
* caching.
|
* caching.
|
||||||
* @param priority The priority of this task.
|
* @param priority The priority of this task.
|
||||||
* @param counters The counters to be set during reading.
|
* @param counters Counters to be set during reading.
|
||||||
* @return Number of read bytes, or 0 if no data is available because the end of the opened range
|
* @return Number of read bytes, or 0 if no data is available because the end of the opened range
|
||||||
* has been reached.
|
* has been reached.
|
||||||
*/
|
*/
|
||||||
|
|
@ -238,8 +213,8 @@ public final class CacheUtil {
|
||||||
C.LENGTH_UNSET, dataSpec.key,
|
C.LENGTH_UNSET, dataSpec.key,
|
||||||
dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH);
|
dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH);
|
||||||
long resolvedLength = dataSource.open(dataSpec);
|
long resolvedLength = dataSource.open(dataSpec);
|
||||||
if (counters.totalBytes == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) {
|
if (counters.contentLength == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) {
|
||||||
counters.totalBytes = dataSpec.absoluteStreamPosition + resolvedLength;
|
counters.contentLength = dataSpec.absoluteStreamPosition + resolvedLength;
|
||||||
}
|
}
|
||||||
long totalRead = 0;
|
long totalRead = 0;
|
||||||
while (totalRead != length) {
|
while (totalRead != length) {
|
||||||
|
|
@ -250,13 +225,13 @@ public final class CacheUtil {
|
||||||
length != C.LENGTH_UNSET ? (int) Math.min(buffer.length, length - totalRead)
|
length != C.LENGTH_UNSET ? (int) Math.min(buffer.length, length - totalRead)
|
||||||
: buffer.length);
|
: buffer.length);
|
||||||
if (read == C.RESULT_END_OF_INPUT) {
|
if (read == C.RESULT_END_OF_INPUT) {
|
||||||
if (counters.totalBytes == C.LENGTH_UNSET) {
|
if (counters.contentLength == C.LENGTH_UNSET) {
|
||||||
counters.totalBytes = dataSpec.absoluteStreamPosition + totalRead;
|
counters.contentLength = dataSpec.absoluteStreamPosition + totalRead;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
totalRead += read;
|
totalRead += read;
|
||||||
counters.downloadedBytes += read;
|
counters.newlyCachedBytes += read;
|
||||||
}
|
}
|
||||||
return totalRead;
|
return totalRead;
|
||||||
} catch (PriorityTaskManager.PriorityTooLowException exception) {
|
} catch (PriorityTaskManager.PriorityTooLowException exception) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue