diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java index 142b846a97..3f57cba1b0 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java @@ -78,16 +78,19 @@ import javax.crypto.spec.SecretKeySpec; throw new RuntimeException(e); } - cipherInputStream = new CipherInputStream( - new DataSourceInputStream(upstream, dataSpec), cipher); + DataSourceInputStream inputStream = new DataSourceInputStream(upstream, dataSpec); + cipherInputStream = new CipherInputStream(inputStream, cipher); + inputStream.open(); return C.LENGTH_UNSET; } @Override public void close() throws IOException { - cipherInputStream = null; - upstream.close(); + if (cipherInputStream != null) { + cipherInputStream = null; + upstream.close(); + } } @Override diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/Aes128DataSourceTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/Aes128DataSourceTest.java new file mode 100644 index 0000000000..86bffc7762 --- /dev/null +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/Aes128DataSourceTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.hls; + +import static com.google.common.truth.Truth.assertThat; + +import android.net.Uri; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import java.io.IOException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** Test for {@link Aes128DataSource}. */ +@RunWith(RobolectricTestRunner.class) +public class Aes128DataSourceTest { + + @Test + public void test_OpenCallsUpstreamOpen_CloseCallsUpstreamClose() throws IOException { + UpstreamDataSource upstream = new UpstreamDataSource(); + Aes128DataSource testInstance = new Aes128DataSource(upstream, new byte[16], new byte[16]); + assertThat(upstream.opened).isFalse(); + + Uri uri = Uri.parse("http.abc.com/def"); + testInstance.open(new DataSpec(uri)); + assertThat(upstream.opened).isTrue(); + + testInstance.close(); + assertThat(upstream.opened).isFalse(); + } + + @Test + public void test_OpenCallsUpstreamThrowingOpen_CloseCallsUpstreamClose() throws IOException { + UpstreamDataSource upstream = + new UpstreamDataSource() { + @Override + public long open(DataSpec dataSpec) throws IOException { + throw new IOException(); + } + }; + Aes128DataSource testInstance = new Aes128DataSource(upstream, new byte[16], new byte[16]); + assertThat(upstream.opened).isFalse(); + + Uri uri = Uri.parse("http.abc.com/def"); + try { + testInstance.open(new DataSpec(uri)); + } catch (IOException e) { + // Expected. + } + assertThat(upstream.opened).isFalse(); + assertThat(upstream.closedCalled).isFalse(); + + // Even though the upstream open call failed, close should still call close on the upstream as + // per the contract of DataSource. + testInstance.close(); + assertThat(upstream.closedCalled).isTrue(); + } + + private static class UpstreamDataSource implements DataSource { + + public boolean opened; + public boolean closedCalled; + + @Override + public long open(DataSpec dataSpec) throws IOException { + opened = true; + return C.LENGTH_UNSET; + } + + @Override + public int read(byte[] buffer, int offset, int readLength) { + return C.RESULT_END_OF_INPUT; + } + + @Override + public Uri getUri() { + return null; + } + + @Override + public void close() { + opened = false; + closedCalled = true; + } + } +}