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
This commit is contained in:
ibaker 2019-10-02 11:50:35 +01:00 committed by Oliver Woodman
parent 15df31b995
commit e0c8cbe21e
5 changed files with 62 additions and 27 deletions

View File

@ -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) ###

View File

@ -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 final class IcyDecoder implements MetadataDecoder {
return decode(Util.fromUtf8Bytes(data, 0, length));
}
@Nullable
@VisibleForTesting
/* package */ Metadata decode(String metadata) {
String name = null;
@ -62,12 +58,9 @@ public final class IcyDecoder implements MetadataDecoder {
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));
}
}

View File

@ -19,26 +19,35 @@ import android.os.Parcel;
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 final class IcyInfo implements Metadata.Entry {
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);
}

View File

@ -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 final class IcyDecoderTest {
@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_emptyTitle() {
public void decode_extraTags() {
String icyContent =
"StreamTitle='test title';StreamURL='test_url';CustomTag|withWeirdSeparator";
IcyDecoder decoder = new IcyDecoder();
Metadata metadata = decoder.decode("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).isEqualTo("test title");
assertThat(streamInfo.url).isEqualTo("test_url");
}
@Test
public void decode_emptyTitle() {
IcyDecoder decoder = new IcyDecoder();
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 final class IcyDecoderTest {
@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 final class IcyDecoderTest {
@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 final class IcyDecoderTest {
@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();
}
}

View File

@ -24,11 +24,11 @@ import org.junit.runner.RunWith;
/** 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);