contentTypePredicate) {
+ this.contentTypePredicate = contentTypePredicate;
+ return this;
+ }
+
+ public Builder setCacheControl(@NonNull final CacheControl cacheControl) {
+ this.cacheControl = cacheControl;
+ return this;
+ }
+
+ public Builder setDefaultRequestProperties(
+ @NonNull final RequestProperties defaultRequestProperties) {
+ this.defaultRequestProperties = defaultRequestProperties;
+ return this;
+ }
+
+ public Builder setIcyHeadersListener(
+ @NonNull final IcyHttpDataSource.IcyHeadersListener icyHeadersListener) {
+ this.icyHeadersListener = icyHeadersListener;
+ return this;
+ }
+
+ public Builder setIcyMetadataListener(@NonNull final IcyMetadataListener icyMetadataListener) {
+ this.icyMetadataListener = icyMetadataListener;
+ return this;
+ }
+
+ IcyHttpDataSource build() {
+ final IcyHttpDataSource dataSource =
+ new IcyHttpDataSource(callFactory,
+ userAgent,
+ contentTypePredicate,
+ cacheControl,
+ defaultRequestProperties);
+ dataSource.icyHeadersListener = icyHeadersListener;
+ dataSource.icyMetadataListener = icyMetadataListener;
+ return dataSource;
+ }
+ }
+
+ /**
+ * Container for Icy headers such as stream genre or name.
+ */
+ public final class IcyHeaders {
+
+ /**
+ * icy-br Bit rate in KB/s
+ */
+ int bitRate;
+ /**
+ * icy-genre
+ */
+ String genre;
+ /**
+ * icy-name
+ */
+ String name;
+ /**
+ * icy-url
+ */
+ String url;
+ /**
+ * icy-pub
+ */
+ boolean isPublic;
+
+ /**
+ * @return The bit rate in kilobits per second (KB/s)
+ */
+ public int getBitRate() {
+ return bitRate;
+ }
+
+ /**
+ * @return The musical genre of the stream
+ */
+ public String getGenre() {
+ return genre;
+ }
+
+ /**
+ * @return The stream name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return The URL of the music stream (can be a website or artwork)
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * @return Determines if this stream is public or listed in a catalog
+ */
+ public boolean isPublic() {
+ return isPublic;
+ }
+
+ @Override
+ public String toString() {
+ return "IcyHeaders{" +
+ "bitRate='" + bitRate + '\'' +
+ ", genre='" + genre + '\'' +
+ ", name='" + name + '\'' +
+ ", url='" + url + '\'' +
+ ", isPublic=" + isPublic +
+ '}';
+ }
+ }
+
+ /**
+ * Container for stream title and URL.
+ *
+ * The exact contents isn't specified and implementation specific. It's therefore up to the user
+ * to figure what format a given stream returns.
+ */
+ public final class IcyMetadata {
+
+ String streamTitle;
+ String streamUrl;
+ HashMap metadata = new HashMap<>();
+
+ /**
+ * @return The song title.
+ */
+ public String getStreamTitle() {
+ return streamTitle;
+ }
+
+ /**
+ * @return Url to album artwork or more information about the current song.
+ */
+ public String getStreamUrl() {
+ return streamUrl;
+ }
+
+ /**
+ * Provides a map of all stream metadata.
+ *
+ * @return Complete metadata
+ */
+ public HashMap getMetadata() {
+ return metadata;
+ }
+
+ @Override
+ public String toString() {
+ return "IcyMetadata{" +
+ "streamTitle='" + streamTitle + '\'' +
+ ", streamUrl='" + streamUrl + '\'' +
+ ", metadata='" + metadata + '\'' +
+ '}';
+ }
+ }
+}
diff --git a/extensions/icy/src/main/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactory.java b/extensions/icy/src/main/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactory.java
new file mode 100644
index 0000000000..e396405f44
--- /dev/null
+++ b/extensions/icy/src/main/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactory.java
@@ -0,0 +1,85 @@
+package com.google.android.exoplayer2.ext.icy;
+
+import android.support.annotation.NonNull;
+
+import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource;
+import com.google.android.exoplayer2.upstream.HttpDataSource;
+import com.google.android.exoplayer2.util.Predicate;
+
+import okhttp3.CacheControl;
+import okhttp3.Call;
+
+/**
+ * A {@link HttpDataSource.Factory} that produces {@link IcyHttpDataSource} instances.
+ */
+public final class IcyHttpDataSourceFactory extends OkHttpDataSource.BaseFactory {
+
+ private Call.Factory callFactory;
+ private String userAgent;
+ private Predicate contentTypePredicate;
+ private CacheControl cacheControl;
+ private IcyHttpDataSource.IcyHeadersListener icyHeadersListener;
+ private IcyHttpDataSource.IcyMetadataListener icyMetadataListener;
+
+ private IcyHttpDataSourceFactory() {
+ // See class Builder
+ }
+
+ /**
+ * Constructs a IcyHttpDataSourceFactory.
+ */
+ public final static class Builder {
+
+ private final IcyHttpDataSourceFactory factory;
+
+ public Builder(@NonNull Call.Factory callFactory) {
+ // Apply defaults
+ factory = new IcyHttpDataSourceFactory();
+ factory.callFactory = callFactory;
+ }
+
+ public Builder setUserAgent(@NonNull final String userAgent) {
+ factory.userAgent = userAgent;
+ return this;
+ }
+
+ public Builder setContentTypePredicate(@NonNull final Predicate contentTypePredicate) {
+ factory.contentTypePredicate = contentTypePredicate;
+ return this;
+ }
+
+ public Builder setCacheControl(@NonNull final CacheControl cacheControl) {
+ factory.cacheControl = cacheControl;
+ return this;
+ }
+
+ public Builder setIcyHeadersListener(
+ @NonNull final IcyHttpDataSource.IcyHeadersListener icyHeadersListener) {
+ factory.icyHeadersListener = icyHeadersListener;
+ return this;
+ }
+
+ public Builder setIcyMetadataChangeListener(
+ @NonNull final IcyHttpDataSource.IcyMetadataListener icyMetadataListener) {
+ factory.icyMetadataListener = icyMetadataListener;
+ return this;
+ }
+
+ public IcyHttpDataSourceFactory build() {
+ return factory;
+ }
+ }
+
+ @Override
+ protected IcyHttpDataSource createDataSourceInternal(
+ @NonNull HttpDataSource.RequestProperties defaultRequestProperties) {
+ return new IcyHttpDataSource.Builder(callFactory)
+ .setUserAgent(userAgent)
+ .setContentTypePredicate(contentTypePredicate)
+ .setCacheControl(cacheControl)
+ .setDefaultRequestProperties(defaultRequestProperties)
+ .setIcyHeadersListener(icyHeadersListener)
+ .setIcyMetadataListener(icyMetadataListener)
+ .build();
+ }
+}
diff --git a/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactoryTest.java b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactoryTest.java
new file mode 100644
index 0000000000..11f5e074d4
--- /dev/null
+++ b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceFactoryTest.java
@@ -0,0 +1,41 @@
+package com.google.android.exoplayer2.ext.icy;
+
+import com.google.android.exoplayer2.upstream.HttpDataSource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import okhttp3.OkHttpClient;
+import com.google.android.exoplayer2.ext.icy.test.Constants;
+
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public final class IcyHttpDataSourceFactoryTest {
+
+ private final IcyHttpDataSource.IcyHeadersListener TEST_ICY_HEADERS_LISTENER = icyHeaders -> {
+ };
+ private final IcyHttpDataSource.IcyMetadataListener TEST_ICY_METADATA_LISTENER = icyMetadata -> {
+ };
+
+ @Test
+ public void createDataSourceViaFactoryFromFactoryBuilder() {
+ // Arrange
+ OkHttpClient client = new OkHttpClient.Builder().build();
+ IcyHttpDataSourceFactory factory = new IcyHttpDataSourceFactory.Builder(client)
+ .setUserAgent(Constants.TEST_USER_AGENT)
+ .setIcyHeadersListener(TEST_ICY_HEADERS_LISTENER)
+ .setIcyMetadataChangeListener(TEST_ICY_METADATA_LISTENER)
+ .build();
+ HttpDataSource.RequestProperties requestProperties = new HttpDataSource.RequestProperties();
+
+ // Act
+ IcyHttpDataSource source = factory.createDataSourceInternal(requestProperties);
+
+ // Assert
+ assertNotNull(source);
+ }
+}
diff --git a/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceTest.java b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceTest.java
new file mode 100644
index 0000000000..b06bd78e65
--- /dev/null
+++ b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/IcyHttpDataSourceTest.java
@@ -0,0 +1,29 @@
+package com.google.android.exoplayer2.ext.icy;
+
+import com.google.android.exoplayer2.ext.icy.IcyHttpDataSource;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import okhttp3.OkHttpClient;
+import com.google.android.exoplayer2.ext.icy.test.Constants;
+
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public final class IcyHttpDataSourceTest {
+
+ @Test
+ public void createDataSourceFromBuilder() {
+ // Arrange, act
+ OkHttpClient client = new OkHttpClient.Builder().build();
+ IcyHttpDataSource source = new IcyHttpDataSource.Builder(client)
+ .setUserAgent(Constants.TEST_USER_AGENT)
+ .build();
+
+ // Assert
+ assertNotNull(source);
+ }
+}
diff --git a/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/test/Constants.java b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/test/Constants.java
new file mode 100644
index 0000000000..6dec462829
--- /dev/null
+++ b/extensions/icy/src/test/java/com/google/android/exoplayer2/ext/icy/test/Constants.java
@@ -0,0 +1,6 @@
+package com.google.android.exoplayer2.ext.icy.test;
+
+public final class Constants {
+
+ public static final String TEST_USER_AGENT = "test-agent";
+}