use of com.google.android.exoplayer2.upstream.cache.Cache in project ExoPlayer by google.
the class CacheDataSource method openNextSource.
/**
* Opens the next source. If the cache contains data spanning the current read position then
* {@link #cacheReadDataSource} is opened to read from it. Else {@link #upstreamDataSource} is
* opened to read from the upstream source and write into the cache.
*
* <p>There must not be a currently open source when this method is called, except in the case
* that {@code checkCache} is true. If {@code checkCache} is true then there must be a currently
* open source, and it must be {@link #upstreamDataSource}. It will be closed and a new source
* opened if it's possible to switch to reading from or writing to the cache. If a switch isn't
* possible then the current source is left unchanged.
*
* @param requestDataSpec The original {@link DataSpec} to build upon for the next source.
* @param checkCache If true tries to switch to reading from or writing to cache instead of
* reading from {@link #upstreamDataSource}, which is the currently open source.
*/
private void openNextSource(DataSpec requestDataSpec, boolean checkCache) throws IOException {
@Nullable CacheSpan nextSpan;
String key = castNonNull(requestDataSpec.key);
if (currentRequestIgnoresCache) {
nextSpan = null;
} else if (blockOnCache) {
try {
nextSpan = cache.startReadWrite(key, readPosition, bytesRemaining);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new InterruptedIOException();
}
} else {
nextSpan = cache.startReadWriteNonBlocking(key, readPosition, bytesRemaining);
}
DataSpec nextDataSpec;
DataSource nextDataSource;
if (nextSpan == null) {
// The data is locked in the cache, or we're ignoring the cache. Bypass the cache and read
// from upstream.
nextDataSource = upstreamDataSource;
nextDataSpec = requestDataSpec.buildUpon().setPosition(readPosition).setLength(bytesRemaining).build();
} else if (nextSpan.isCached) {
// Data is cached in a span file starting at nextSpan.position.
Uri fileUri = Uri.fromFile(castNonNull(nextSpan.file));
long filePositionOffset = nextSpan.position;
long positionInFile = readPosition - filePositionOffset;
long length = nextSpan.length - positionInFile;
if (bytesRemaining != C.LENGTH_UNSET) {
length = min(length, bytesRemaining);
}
nextDataSpec = requestDataSpec.buildUpon().setUri(fileUri).setUriPositionOffset(filePositionOffset).setPosition(positionInFile).setLength(length).build();
nextDataSource = cacheReadDataSource;
} else {
// Data is not cached, and data is not locked, read from upstream with cache backing.
long length;
if (nextSpan.isOpenEnded()) {
length = bytesRemaining;
} else {
length = nextSpan.length;
if (bytesRemaining != C.LENGTH_UNSET) {
length = min(length, bytesRemaining);
}
}
nextDataSpec = requestDataSpec.buildUpon().setPosition(readPosition).setLength(length).build();
if (cacheWriteDataSource != null) {
nextDataSource = cacheWriteDataSource;
} else {
nextDataSource = upstreamDataSource;
cache.releaseHoleSpan(nextSpan);
nextSpan = null;
}
}
checkCachePosition = !currentRequestIgnoresCache && nextDataSource == upstreamDataSource ? readPosition + MIN_READ_BEFORE_CHECKING_CACHE : Long.MAX_VALUE;
if (checkCache) {
Assertions.checkState(isBypassingCache());
if (nextDataSource == upstreamDataSource) {
// Continue reading from upstream.
return;
}
// We're switching to reading from or writing to the cache.
try {
closeCurrentSource();
} catch (Throwable e) {
if (castNonNull(nextSpan).isHoleSpan()) {
// Release the hole span before throwing, else we'll hold it forever.
cache.releaseHoleSpan(nextSpan);
}
throw e;
}
}
if (nextSpan != null && nextSpan.isHoleSpan()) {
currentHoleSpan = nextSpan;
}
currentDataSource = nextDataSource;
currentDataSpec = nextDataSpec;
currentDataSourceBytesRead = 0;
long resolvedLength = nextDataSource.open(nextDataSpec);
// Update bytesRemaining, actualUri and (if writing to cache) the cache metadata.
ContentMetadataMutations mutations = new ContentMetadataMutations();
if (nextDataSpec.length == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) {
bytesRemaining = resolvedLength;
ContentMetadataMutations.setContentLength(mutations, readPosition + bytesRemaining);
}
if (isReadingFromUpstream()) {
actualUri = nextDataSource.getUri();
boolean isRedirected = !requestDataSpec.uri.equals(actualUri);
ContentMetadataMutations.setRedirectedUri(mutations, isRedirected ? actualUri : null);
}
if (isWritingToCache()) {
cache.applyContentMetadataMutations(key, mutations);
}
}
use of com.google.android.exoplayer2.upstream.cache.Cache in project ExoPlayer by google.
the class CacheDataSource method open.
@Override
public long open(DataSpec dataSpec) throws IOException {
try {
String key = cacheKeyFactory.buildCacheKey(dataSpec);
DataSpec requestDataSpec = dataSpec.buildUpon().setKey(key).build();
this.requestDataSpec = requestDataSpec;
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */
requestDataSpec.uri);
readPosition = dataSpec.position;
int reason = shouldIgnoreCacheForRequest(dataSpec);
currentRequestIgnoresCache = reason != CACHE_NOT_IGNORED;
if (currentRequestIgnoresCache) {
notifyCacheIgnored(reason);
}
if (currentRequestIgnoresCache) {
bytesRemaining = C.LENGTH_UNSET;
} else {
bytesRemaining = ContentMetadata.getContentLength(cache.getContentMetadata(key));
if (bytesRemaining != C.LENGTH_UNSET) {
bytesRemaining -= dataSpec.position;
if (bytesRemaining < 0) {
throw new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE);
}
}
}
if (dataSpec.length != C.LENGTH_UNSET) {
bytesRemaining = bytesRemaining == C.LENGTH_UNSET ? dataSpec.length : min(bytesRemaining, dataSpec.length);
}
if (bytesRemaining > 0 || bytesRemaining == C.LENGTH_UNSET) {
openNextSource(requestDataSpec, false);
}
return dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : bytesRemaining;
} catch (Throwable e) {
handleBeforeThrow(e);
throw e;
}
}
use of com.google.android.exoplayer2.upstream.cache.Cache in project ExoPlayer by google.
the class HlsDownloaderTest method setUp.
@Before
public void setUp() throws Exception {
tempFolder = Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor(), TestUtil.getInMemoryDatabaseProvider());
progressListener = new ProgressListener();
fakeDataSet = new FakeDataSet().setData(MULTIVARIANT_PLAYLIST_URI, MULTIVARIANT_PLAYLIST_DATA).setData(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_DATA).setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", 10).setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts", 11).setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence2.ts", 12).setData(MEDIA_PLAYLIST_2_URI, MEDIA_PLAYLIST_DATA).setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence0.ts", 13).setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence1.ts", 14).setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence2.ts", 15);
}
use of com.google.android.exoplayer2.upstream.cache.Cache in project ExoPlayer by google.
the class CacheAsserts method assertDataCached.
/**
* Asserts that the cache contains the given data for {@code dataSpec}.
*
* @throws IOException If an error occurred reading from the Cache.
*/
public static void assertDataCached(Cache cache, DataSpec dataSpec, byte[] expected) throws IOException {
DataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0);
byte[] bytes;
try {
dataSource.open(dataSpec);
bytes = DataSourceUtil.readToEnd(dataSource);
} catch (IOException e) {
throw new IOException("Opening/reading cache failed: " + dataSpec, e);
} finally {
dataSource.close();
}
assertWithMessage("Cached data doesn't match expected for '" + dataSpec.uri + "',").that(bytes).isEqualTo(expected);
}
use of com.google.android.exoplayer2.upstream.cache.Cache in project ExoPlayer by google.
the class CacheAsserts method assertReadData.
/**
* Asserts that the read data from {@code dataSource} specified by {@code dataSpec} is equal to
* {@code expected} or not.
*
* @throws IOException If an error occurred reading from the Cache.
*/
public static void assertReadData(DataSource dataSource, DataSpec dataSpec, byte[] expected) throws IOException {
try (DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec)) {
byte[] bytes = Util.toByteArray(inputStream);
assertThat(bytes).isEqualTo(expected);
}
}
Aggregations