diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java index 57f5a6ad93..61c14272cb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java @@ -43,6 +43,7 @@ public final class CacheDataSink implements DataSink { private final Cache cache; private final long maxCacheFileSize; private final int bufferSize; + private final boolean syncFileDescriptor; private DataSpec dataSpec; private File file; @@ -72,7 +73,20 @@ public final class CacheDataSink implements DataSink { * multiple cache files. */ public CacheDataSink(Cache cache, long maxCacheFileSize) { - this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE); + this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE, true); + } + + /** + * Constructs a CacheDataSink using the {@link #DEFAULT_BUFFER_SIZE}. + * + * @param cache The cache into which data should be written. + * @param maxCacheFileSize The maximum size of a cache file, in bytes. If the sink is opened for + * a {@link DataSpec} whose size exceeds this value, then the data will be fragmented into + * multiple cache files. + * @param syncFileDescriptor Skip file descriptor sync when closing current output stream. + */ + public CacheDataSink(Cache cache, long maxCacheFileSize, boolean syncFileDescriptor) { + this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE, syncFileDescriptor); } /** @@ -82,11 +96,13 @@ public final class CacheDataSink implements DataSink { * multiple cache files. * @param bufferSize The buffer size in bytes for writing to a cache file. A zero or negative * value disables buffering. + * @param syncFileDescriptor Sync file descriptor when closing current output stream. */ - public CacheDataSink(Cache cache, long maxCacheFileSize, int bufferSize) { + public CacheDataSink(Cache cache, long maxCacheFileSize, int bufferSize, boolean syncFileDescriptor) { this.cache = Assertions.checkNotNull(cache); this.maxCacheFileSize = maxCacheFileSize; this.bufferSize = bufferSize; + this.syncFileDescriptor = syncFileDescriptor; } @Override @@ -170,7 +186,9 @@ public final class CacheDataSink implements DataSink { boolean success = false; try { outputStream.flush(); - underlyingFileOutputStream.getFD().sync(); + if (syncFileDescriptor) { + underlyingFileOutputStream.getFD().sync(); + } success = true; } finally { Util.closeQuietly(outputStream); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java index 0b9ab66508..93791f1c12 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.java @@ -44,7 +44,7 @@ public final class CacheDataSinkFactory implements DataSink.Factory { @Override public DataSink createDataSink() { - return new CacheDataSink(cache, maxCacheFileSize, bufferSize); + return new CacheDataSink(cache, maxCacheFileSize, bufferSize, true); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 09be138abe..374fb61c17 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -79,29 +79,49 @@ public final class CacheDataSourceTest { @Test public void testCacheAndRead() throws Exception { - assertCacheAndRead(false, false); + assertCacheAndRead(false, false, true); } @Test public void testCacheAndReadUnboundedRequest() throws Exception { - assertCacheAndRead(true, false); + assertCacheAndRead(true, false, true); } @Test public void testCacheAndReadUnknownLength() throws Exception { - assertCacheAndRead(false, true); + assertCacheAndRead(false, true, true); } @Test public void testCacheAndReadUnboundedRequestUnknownLength() throws Exception { - assertCacheAndRead(true, true); + assertCacheAndRead(true, true, true); + } + + @Test + public void testCacheAndReadSkipFDSync() throws Exception { + assertCacheAndRead(false, false, false); + } + + @Test + public void testCacheAndReadUnboundedRequestSkipFDSync() throws Exception { + assertCacheAndRead(true, false, false); + } + + @Test + public void testCacheAndReadUnknownLengthSkipFDSync() throws Exception { + assertCacheAndRead(false, true, false); + } + + @Test + public void testCacheAndReadUnboundedRequestUnknownLengthSkipFDSync() throws Exception { + assertCacheAndRead(true, true, false); } @Test public void testUnsatisfiableRange() throws Exception { // Bounded request but the content length is unknown. This forces all data to be cached but not // the length - assertCacheAndRead(false, true); + assertCacheAndRead(false, true, true); // Now do an unbounded request. This will read all of the data from cache and then try to read // more from upstream which will cause to a 416 so CDS will store the length. @@ -347,10 +367,11 @@ public final class CacheDataSourceTest { cacheDataSource.close(); } - private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength) + private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength, + boolean syncFD) throws IOException { // Read all data from upstream and write to cache - CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength); + CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength, syncFD); assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength); // Just read from cache @@ -391,14 +412,19 @@ public final class CacheDataSourceTest { private CacheDataSource createCacheDataSource(boolean setReadException, boolean simulateUnknownLength) { - return createCacheDataSource(setReadException, simulateUnknownLength, - CacheDataSource.FLAG_BLOCK_ON_CACHE); + return createCacheDataSource(setReadException, simulateUnknownLength, true); } private CacheDataSource createCacheDataSource(boolean setReadException, - boolean simulateUnknownLength, @CacheDataSource.Flags int flags) { + boolean simulateUnknownLength, boolean syncFD) { + return createCacheDataSource(setReadException, simulateUnknownLength, + CacheDataSource.FLAG_BLOCK_ON_CACHE, syncFD); + } + + private CacheDataSource createCacheDataSource(boolean setReadException, + boolean simulateUnknownLength, @CacheDataSource.Flags int flags, boolean syncFD) { return createCacheDataSource(setReadException, simulateUnknownLength, flags, - new CacheDataSink(cache, MAX_CACHE_FILE_SIZE)); + new CacheDataSink(cache, MAX_CACHE_FILE_SIZE, syncFD)); } private CacheDataSource createCacheDataSource(boolean setReadException,