From 2b9c31a14f177bbfd6c190726dcb5d3fcb75f17b Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 18 May 2018 05:48:48 -0700 Subject: [PATCH] Add MediaSource and DataSource to inject playback nonce into URLs. A new playback nonce is created for each playback of the same item. Thus we need to inject the nonce dynamically into the data source factory. This CL adds the DataSource which does the actual insertion into the request URLs and a MediaSource which listens to new media periods, to request the nonce and to configure the data source factory for this media period to use this nonce. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=197134217 --- .../exoplayer2/upstream/DataSource.java | 3 +- .../android/exoplayer2/upstream/DataSpec.java | 27 +++++++++++---- .../upstream/PriorityDataSource.java | 3 +- .../android/exoplayer2/util/UriUtil.java | 20 +++++++++++ .../android/exoplayer2/util/UriUtilTest.java | 34 +++++++++++++++++++ .../exoplayer2/testutil/FakeDataSource.java | 5 +++ .../exoplayer2/testutil/FakeMediaSource.java | 5 +++ 7 files changed, 89 insertions(+), 8 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java index 4a2354e180..ce3230fa43 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.upstream; import android.net.Uri; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import java.io.IOException; @@ -79,7 +80,7 @@ public interface DataSource { * * @return The {@link Uri} from which data is being read, or null if the source is not open. */ - Uri getUri(); + @Nullable Uri getUri(); /** * Closes the source. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index a6b89a334d..ad7a9d0147 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -61,7 +61,7 @@ public final class DataSpec { /** * Body for a POST request, null otherwise. */ - public final byte[] postBody; + public final @Nullable byte[] postBody; /** * The absolute position of the data in the full stream. */ @@ -81,12 +81,12 @@ public final class DataSpec { * A key that uniquely identifies the original stream. Used for cache indexing. May be null if the * {@link DataSpec} is not intended to be used in conjunction with a cache. */ - @Nullable public final String key; + public final @Nullable String key; /** * Request flags. Currently {@link #FLAG_ALLOW_GZIP} and * {@link #FLAG_ALLOW_CACHING_UNKNOWN_LENGTH} are the only supported flags. */ - @Flags public final int flags; + public final @Flags int flags; /** * Construct a {@link DataSpec} for the given uri and with {@link #key} set to null. @@ -128,7 +128,8 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ - public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key, @Flags int flags) { + public DataSpec( + Uri uri, long absoluteStreamPosition, long length, @Nullable String key, @Flags int flags) { this(uri, absoluteStreamPosition, absoluteStreamPosition, length, key, flags); } @@ -143,7 +144,12 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ - public DataSpec(Uri uri, long absoluteStreamPosition, long position, long length, String key, + public DataSpec( + Uri uri, + long absoluteStreamPosition, + long position, + long length, + @Nullable String key, @Flags int flags) { this(uri, null, absoluteStreamPosition, position, length, key, flags); } @@ -162,7 +168,7 @@ public final class DataSpec { */ public DataSpec( Uri uri, - byte[] postBody, + @Nullable byte[] postBody, long absoluteStreamPosition, long position, long length, @@ -222,4 +228,13 @@ public final class DataSpec { } } + /** + * Returns a copy of this {@link DataSpec} with the specified Uri. + * + * @param uri The new source {@link Uri}. + * @return The copied {@link DataSpec} with the specified Uri. + */ + public DataSpec withUri(Uri uri) { + return new DataSpec(uri, postBody, absoluteStreamPosition, position, length, key, flags); + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java index a36ccd11b1..729f7fe179 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.upstream; import android.net.Uri; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.PriorityTaskManager; import java.io.IOException; @@ -63,7 +64,7 @@ public final class PriorityDataSource implements DataSource { } @Override - public Uri getUri() { + public @Nullable Uri getUri() { return upstream.getUri(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/UriUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/UriUtil.java index 6592273d03..071ebf2084 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/UriUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/UriUtil.java @@ -143,6 +143,26 @@ public final class UriUtil { } } + /** + * Removes query parameter from an Uri, if present. + * + * @param uri The uri. + * @param queryParameterName The name of the query parameter. + * @return The uri without the query parameter. + */ + public static Uri removeQueryParameter(Uri uri, String queryParameterName) { + Uri.Builder builder = uri.buildUpon(); + builder.clearQuery(); + for (String key : uri.getQueryParameterNames()) { + if (!key.equals(queryParameterName)) { + for (String value : uri.getQueryParameters(key)) { + builder.appendQueryParameter(key, value); + } + } + } + return builder.build(); + } + /** * Removes dot segments from the path of a URI. * diff --git a/library/core/src/test/java/com/google/android/exoplayer2/util/UriUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/util/UriUtilTest.java index a52867e1b2..82c62ecb3e 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/util/UriUtilTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/util/UriUtilTest.java @@ -15,9 +15,11 @@ */ package com.google.android.exoplayer2.util; +import static com.google.android.exoplayer2.util.UriUtil.removeQueryParameter; import static com.google.android.exoplayer2.util.UriUtil.resolve; import static com.google.common.truth.Truth.assertThat; +import android.net.Uri; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -104,4 +106,36 @@ public final class UriUtilTest { assertThat(resolve("a:b", "../c")).isEqualTo("a:c"); } + @Test + public void removeOnlyQueryParameter() { + Uri uri = Uri.parse("http://uri?query=value"); + assertThat(removeQueryParameter(uri, "query").toString()).isEqualTo("http://uri"); + } + + @Test + public void removeFirstQueryParameter() { + Uri uri = Uri.parse("http://uri?query=value&second=value2"); + assertThat(removeQueryParameter(uri, "query").toString()).isEqualTo("http://uri?second=value2"); + } + + @Test + public void removeMiddleQueryParameter() { + Uri uri = Uri.parse("http://uri?first=value1&query=value&last=value2"); + assertThat(removeQueryParameter(uri, "query").toString()) + .isEqualTo("http://uri?first=value1&last=value2"); + } + + @Test + public void removeLastQueryParameter() { + Uri uri = Uri.parse("http://uri?first=value1&query=value"); + assertThat(removeQueryParameter(uri, "query").toString()).isEqualTo("http://uri?first=value1"); + } + + @Test + public void removeNonExistentQueryParameter() { + Uri uri = Uri.parse("http://uri"); + assertThat(removeQueryParameter(uri, "foo").toString()).isEqualTo("http://uri"); + uri = Uri.parse("http://uri?query=value"); + assertThat(removeQueryParameter(uri, "foo").toString()).isEqualTo("http://uri?query=value"); + } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index 2675e1f0d7..de623b59c9 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -217,6 +217,11 @@ public class FakeDataSource implements DataSource { return dataSpecs; } + /** Returns whether the data source is currently opened. */ + public final boolean isOpened() { + return opened; + } + protected void onDataRead(int bytesRead) throws IOException { // Do nothing. Can be overridden. } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java index 905adae092..ffc877bf42 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java @@ -159,6 +159,11 @@ public class FakeMediaSource extends BaseMediaSource { } } + /** Asserts that the source has been prepared. */ + public void assertPrepared() { + assertThat(preparedSource).isTrue(); + } + /** * Assert that the source and all periods have been released. */