From e0c8cbe21ea11bbce0bba57faa1f4bca18e2bcb3 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 2 Oct 2019 11:50:35 +0100 Subject: [PATCH] Pass the raw ICY metadata through IcyInfo The ICY 'spec' isn't really clear/tight enough to do anything more specific than this I think. Issue:#6476 PiperOrigin-RevId: 272405322 --- RELEASENOTES.md | 2 + .../exoplayer2/metadata/icy/IcyDecoder.java | 9 +--- .../exoplayer2/metadata/icy/IcyInfo.java | 26 +++++++---- .../metadata/icy/IcyDecoderTest.java | 46 +++++++++++++++---- ...cyStreamInfoTest.java => IcyInfoTest.java} | 4 +- 5 files changed, 61 insertions(+), 26 deletions(-) rename library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/{IcyStreamInfoTest.java => IcyInfoTest.java} (91%) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0cc0a8d1496..8f9f78f629c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,6 +5,8 @@ * Add `Player.onPlaybackSuppressionReasonChanged` to allow listeners to detect playbacks suppressions (e.g. audio focus loss) directly ([#6203](https://github.com/google/ExoPlayer/issues/6203)). +* Expose the raw ICY metadata through `IcyInfo` + ([#6476](https://github.com/google/ExoPlayer/issues/6476)). ### 2.10.5 (2019-09-20) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java index 3d873926bbe..a148c03b65d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java @@ -15,12 +15,10 @@ */ package com.google.android.exoplayer2.metadata.icy; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataDecoder; import com.google.android.exoplayer2.metadata.MetadataInputBuffer; -import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.util.regex.Matcher; @@ -36,7 +34,6 @@ public final class IcyDecoder implements MetadataDecoder { private static final String STREAM_KEY_URL = "streamurl"; @Override - @Nullable @SuppressWarnings("ByteBufferBackingArray") public Metadata decode(MetadataInputBuffer inputBuffer) { ByteBuffer buffer = inputBuffer.data; @@ -45,7 +42,6 @@ public Metadata decode(MetadataInputBuffer inputBuffer) { return decode(Util.fromUtf8Bytes(data, 0, length)); } - @Nullable @VisibleForTesting /* package */ Metadata decode(String metadata) { String name = null; @@ -62,12 +58,9 @@ public Metadata decode(MetadataInputBuffer inputBuffer) { case STREAM_KEY_URL: url = value; break; - default: - Log.w(TAG, "Unrecognized ICY tag: " + name); - break; } index = matcher.end(); } - return (name != null || url != null) ? new Metadata(new IcyInfo(name, url)) : null; + return new Metadata(new IcyInfo(metadata, name, url)); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java index e6b915a6c80..717bb2b2e25 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java @@ -19,26 +19,35 @@ import android.os.Parcelable; import androidx.annotation.Nullable; import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; /** ICY in-stream information. */ public final class IcyInfo implements Metadata.Entry { + /** The complete metadata string used to construct this IcyInfo. */ + public final String rawMetadata; /** The stream title if present, or {@code null}. */ @Nullable public final String title; - /** The stream title if present, or {@code null}. */ + /** The stream URL if present, or {@code null}. */ @Nullable public final String url; /** + * Construct a new IcyInfo from the source metadata string, and optionally a StreamTitle & + * StreamUrl that have been extracted. + * + * @param rawMetadata See {@link #rawMetadata}. * @param title See {@link #title}. * @param url See {@link #url}. */ - public IcyInfo(@Nullable String title, @Nullable String url) { + public IcyInfo(String rawMetadata, @Nullable String title, @Nullable String url) { + this.rawMetadata = rawMetadata; this.title = title; this.url = url; } /* package */ IcyInfo(Parcel in) { + rawMetadata = Assertions.checkNotNull(in.readString()); title = in.readString(); url = in.readString(); } @@ -52,26 +61,27 @@ public boolean equals(@Nullable Object obj) { return false; } IcyInfo other = (IcyInfo) obj; - return Util.areEqual(title, other.title) && Util.areEqual(url, other.url); + // title & url are derived from rawMetadata, so no need to include them in the comparison. + return Util.areEqual(rawMetadata, other.rawMetadata); } @Override public int hashCode() { - int result = 17; - result = 31 * result + (title != null ? title.hashCode() : 0); - result = 31 * result + (url != null ? url.hashCode() : 0); - return result; + // title & url are derived from rawMetadata, so no need to include them in the hash. + return rawMetadata.hashCode(); } @Override public String toString() { - return "ICY: title=\"" + title + "\", url=\"" + url + "\""; + return String.format( + "ICY: title=\"%s\", url=\"%s\", rawMetadata=\"%s\"", title, url, rawMetadata); } // Parcelable implementation. @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(rawMetadata); dest.writeString(title); dest.writeString(url); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java index 4602d172a66..72237d665c8 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java @@ -29,10 +29,12 @@ public final class IcyDecoderTest { @Test public void decode() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='test title';StreamURL='test_url';"); + String icyContent = "StreamTitle='test title';StreamURL='test_url';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEqualTo("test title"); assertThat(streamInfo.url).isEqualTo("test_url"); } @@ -40,21 +42,39 @@ public void decode() { @Test public void decode_titleOnly() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='test title';"); + String icyContent = "StreamTitle='test title';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEqualTo("test title"); assertThat(streamInfo.url).isNull(); } + @Test + public void decode_extraTags() { + String icyContent = + "StreamTitle='test title';StreamURL='test_url';CustomTag|withWeirdSeparator"; + IcyDecoder decoder = new IcyDecoder(); + Metadata metadata = decoder.decode(icyContent); + + assertThat(metadata.length()).isEqualTo(1); + IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); + assertThat(streamInfo.title).isEqualTo("test title"); + assertThat(streamInfo.url).isEqualTo("test_url"); + } + @Test public void decode_emptyTitle() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='';StreamURL='test_url';"); + String icyContent = "StreamTitle='';StreamURL='test_url';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEmpty(); assertThat(streamInfo.url).isEqualTo("test_url"); } @@ -62,10 +82,12 @@ public void decode_emptyTitle() { @Test public void decode_semiColonInTitle() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='test; title';StreamURL='test_url';"); + String icyContent = "StreamTitle='test; title';StreamURL='test_url';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEqualTo("test; title"); assertThat(streamInfo.url).isEqualTo("test_url"); } @@ -73,10 +95,12 @@ public void decode_semiColonInTitle() { @Test public void decode_quoteInTitle() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='test' title';StreamURL='test_url';"); + String icyContent = "StreamTitle='test' title';StreamURL='test_url';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEqualTo("test' title"); assertThat(streamInfo.url).isEqualTo("test_url"); } @@ -84,19 +108,25 @@ public void decode_quoteInTitle() { @Test public void decode_lineTerminatorInTitle() { IcyDecoder decoder = new IcyDecoder(); - Metadata metadata = decoder.decode("StreamTitle='test\r\ntitle';StreamURL='test_url';"); + String icyContent = "StreamTitle='test\r\ntitle';StreamURL='test_url';"; + Metadata metadata = decoder.decode(icyContent); assertThat(metadata.length()).isEqualTo(1); IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo(icyContent); assertThat(streamInfo.title).isEqualTo("test\r\ntitle"); assertThat(streamInfo.url).isEqualTo("test_url"); } @Test - public void decode_notIcy() { + public void decode_noReconisedHeaders() { IcyDecoder decoder = new IcyDecoder(); Metadata metadata = decoder.decode("NotIcyData"); - assertThat(metadata).isNull(); + assertThat(metadata.length()).isEqualTo(1); + IcyInfo streamInfo = (IcyInfo) metadata.get(0); + assertThat(streamInfo.rawMetadata).isEqualTo("NotIcyData"); + assertThat(streamInfo.title).isNull(); + assertThat(streamInfo.url).isNull(); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyInfoTest.java similarity index 91% rename from library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java rename to library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyInfoTest.java index 2bffe171d35..2c8e6616c97 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyInfoTest.java @@ -24,11 +24,11 @@ /** Test for {@link IcyInfo}. */ @RunWith(AndroidJUnit4.class) -public final class IcyStreamInfoTest { +public final class IcyInfoTest { @Test public void parcelEquals() { - IcyInfo streamInfo = new IcyInfo("name", "url"); + IcyInfo streamInfo = new IcyInfo("StreamName='name';StreamUrl='url'", "name", "url"); // Write to parcel. Parcel parcel = Parcel.obtain(); streamInfo.writeToParcel(parcel, 0);