Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
be2636c3
authored
Dec 18, 2018
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #4993 from saschpe:icy
PiperOrigin-RevId: 226031838
parents
0e8e9621
535b4053
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
984 additions
and
67 deletions
RELEASENOTES.md
extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java
extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/Format.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyHeaders.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java
library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
library/core/src/main/java/com/google/android/exoplayer2/source/IcyDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyHeadersTest.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java
RELEASENOTES.md
View file @
be2636c3
...
@@ -7,7 +7,6 @@
...
@@ -7,7 +7,6 @@
*
Support for playing spherical videos on Daydream.
*
Support for playing spherical videos on Daydream.
*
Improve decoder re-use between playbacks. TODO: Write and link a blog post
*
Improve decoder re-use between playbacks. TODO: Write and link a blog post
here (
[
#2826
](
https://github.com/google/ExoPlayer/issues/2826
)
).
here (
[
#2826
](
https://github.com/google/ExoPlayer/issues/2826
)
).
*
Use the true bitrate for constant-bitrate MP3 seeking.
*
Track selection:
*
Track selection:
*
Add options for controlling audio track selections to
`DefaultTrackSelector`
*
Add options for controlling audio track selections to
`DefaultTrackSelector`
(
[
#3314
](
https://github.com/google/ExoPlayer/issues/3314
)
).
(
[
#3314
](
https://github.com/google/ExoPlayer/issues/3314
)
).
...
@@ -36,8 +35,12 @@
...
@@ -36,8 +35,12 @@
*
DownloadManager:
*
DownloadManager:
*
Create only one task for all DownloadActions for the same content.
*
Create only one task for all DownloadActions for the same content.
*
Rename TaskState to DownloadState.
*
Rename TaskState to DownloadState.
*
MP3: Fix issue where streams would play twice on some Samsung devices
*
MP3:
(
[
#4519
](
https://github.com/google/ExoPlayer/issues/4519
)
).
*
Use the true bitrate for constant-bitrate MP3 seeking.
*
Fix issue where streams would play twice on some Samsung devices
(
[
#4519
](
https://github.com/google/ExoPlayer/issues/4519
)
).
*
Add support for SHOUTcast ICY metadata
(
[
#3735
](
https://github.com/google/ExoPlayer/issues/3735
)
).
### 2.9.2 ###
### 2.9.2 ###
...
...
extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java
View file @
be2636c3
...
@@ -20,6 +20,7 @@ import android.support.annotation.Nullable;
...
@@ -20,6 +20,7 @@ import android.support.annotation.Nullable;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.upstream.BaseDataSource
;
import
com.google.android.exoplayer2.upstream.BaseDataSource
;
import
com.google.android.exoplayer2.upstream.DataSourceException
;
import
com.google.android.exoplayer2.upstream.DataSourceException
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
...
@@ -493,6 +494,11 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
...
@@ -493,6 +494,11 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
if
(
dataSpec
.
httpBody
!=
null
&&
!
isContentTypeHeaderSet
)
{
if
(
dataSpec
.
httpBody
!=
null
&&
!
isContentTypeHeaderSet
)
{
throw
new
IOException
(
"HTTP request with non-empty body must set Content-Type"
);
throw
new
IOException
(
"HTTP request with non-empty body must set Content-Type"
);
}
}
if
(
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_ICY_METADATA
))
{
requestBuilder
.
addHeader
(
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_NAME
,
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_VALUE
);
}
// Set the Range header.
// Set the Range header.
if
(
dataSpec
.
position
!=
0
||
dataSpec
.
length
!=
C
.
LENGTH_UNSET
)
{
if
(
dataSpec
.
position
!=
0
||
dataSpec
.
length
!=
C
.
LENGTH_UNSET
)
{
StringBuilder
rangeValue
=
new
StringBuilder
();
StringBuilder
rangeValue
=
new
StringBuilder
();
...
...
extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java
View file @
be2636c3
...
@@ -21,6 +21,7 @@ import android.net.Uri;
...
@@ -21,6 +21,7 @@ import android.net.Uri;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.upstream.BaseDataSource
;
import
com.google.android.exoplayer2.upstream.BaseDataSource
;
import
com.google.android.exoplayer2.upstream.DataSourceException
;
import
com.google.android.exoplayer2.upstream.DataSourceException
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
...
@@ -263,7 +264,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
...
@@ -263,7 +264,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
private
Request
makeRequest
(
DataSpec
dataSpec
)
throws
HttpDataSourceException
{
private
Request
makeRequest
(
DataSpec
dataSpec
)
throws
HttpDataSourceException
{
long
position
=
dataSpec
.
position
;
long
position
=
dataSpec
.
position
;
long
length
=
dataSpec
.
length
;
long
length
=
dataSpec
.
length
;
boolean
allowGzip
=
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_GZIP
);
HttpUrl
url
=
HttpUrl
.
parse
(
dataSpec
.
uri
.
toString
());
HttpUrl
url
=
HttpUrl
.
parse
(
dataSpec
.
uri
.
toString
());
if
(
url
==
null
)
{
if
(
url
==
null
)
{
...
@@ -293,10 +293,14 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
...
@@ -293,10 +293,14 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
if
(
userAgent
!=
null
)
{
if
(
userAgent
!=
null
)
{
builder
.
addHeader
(
"User-Agent"
,
userAgent
);
builder
.
addHeader
(
"User-Agent"
,
userAgent
);
}
}
if
(!
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_GZIP
))
{
if
(!
allowGzip
)
{
builder
.
addHeader
(
"Accept-Encoding"
,
"identity"
);
builder
.
addHeader
(
"Accept-Encoding"
,
"identity"
);
}
}
if
(
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_ICY_METADATA
))
{
builder
.
addHeader
(
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_NAME
,
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_VALUE
);
}
RequestBody
requestBody
=
null
;
RequestBody
requestBody
=
null
;
if
(
dataSpec
.
httpBody
!=
null
)
{
if
(
dataSpec
.
httpBody
!=
null
)
{
requestBody
=
RequestBody
.
create
(
null
,
dataSpec
.
httpBody
);
requestBody
=
RequestBody
.
create
(
null
,
dataSpec
.
httpBody
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/Format.java
View file @
be2636c3
...
@@ -1274,6 +1274,37 @@ public final class Format implements Parcelable {
...
@@ -1274,6 +1274,37 @@ public final class Format implements Parcelable {
metadata
);
metadata
);
}
}
public
Format
copyWithBitrate
(
int
bitrate
)
{
return
new
Format
(
id
,
label
,
containerMimeType
,
sampleMimeType
,
codecs
,
bitrate
,
maxInputSize
,
width
,
height
,
frameRate
,
rotationDegrees
,
pixelWidthHeightRatio
,
projectionData
,
stereoMode
,
colorInfo
,
channelCount
,
sampleRate
,
pcmEncoding
,
encoderDelay
,
encoderPadding
,
selectionFlags
,
language
,
accessibilityChannel
,
subsampleOffsetUs
,
initializationData
,
drmInitData
,
metadata
);
}
/**
/**
* Returns the number of pixels if this is a video format whose {@link #width} and {@link #height}
* Returns the number of pixels if this is a video format whose {@link #width} and {@link #height}
* are known, or {@link #NO_VALUE} otherwise
* are known, or {@link #NO_VALUE} otherwise
...
...
library/core/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java
View file @
be2636c3
...
@@ -18,8 +18,10 @@ package com.google.android.exoplayer2.metadata;
...
@@ -18,8 +18,10 @@ package com.google.android.exoplayer2.metadata;
import
android.os.Parcel
;
import
android.os.Parcel
;
import
android.os.Parcelable
;
import
android.os.Parcelable
;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.util.Util
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.compatqual.NullableType
;
/**
/**
* A collection of metadata entries.
* A collection of metadata entries.
...
@@ -76,6 +78,18 @@ public final class Metadata implements Parcelable {
...
@@ -76,6 +78,18 @@ public final class Metadata implements Parcelable {
return
entries
[
index
];
return
entries
[
index
];
}
}
/**
* Returns a copy of this metadata with the specified entries appended.
*
* @param entriesToAppend The entries to append.
* @return The metadata instance with the appended entries.
*/
public
Metadata
copyWithAppendedEntries
(
Entry
...
entriesToAppend
)
{
@NullableType
Entry
[]
merged
=
Arrays
.
copyOf
(
entries
,
entries
.
length
+
entriesToAppend
.
length
);
System
.
arraycopy
(
entriesToAppend
,
0
,
merged
,
entries
.
length
,
entriesToAppend
.
length
);
return
new
Metadata
(
Util
.
castNonNullTypeArray
(
merged
));
}
@Override
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
public
boolean
equals
(
@Nullable
Object
obj
)
{
if
(
this
==
obj
)
{
if
(
this
==
obj
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java
View file @
be2636c3
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.metadata;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.metadata;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder
;
import
com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder
;
import
com.google.android.exoplayer2.metadata.icy.IcyDecoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder
;
import
com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
...
@@ -46,38 +47,43 @@ public interface MetadataDecoderFactory {
...
@@ -46,38 +47,43 @@ public interface MetadataDecoderFactory {
/**
/**
* Default {@link MetadataDecoder} implementation.
* Default {@link MetadataDecoder} implementation.
* <p>
*
* The formats supported by this factory are:
* <p>The formats supported by this factory are:
*
* <ul>
* <ul>
* <li>ID3 ({@link Id3Decoder})</li>
* <li>ID3 ({@link Id3Decoder})
* <li>EMSG ({@link EventMessageDecoder})</li>
* <li>EMSG ({@link EventMessageDecoder})
* <li>SCTE-35 ({@link SpliceInfoDecoder})</li>
* <li>SCTE-35 ({@link SpliceInfoDecoder})
* <li>ICY ({@link IcyDecoder})
* </ul>
* </ul>
*/
*/
MetadataDecoderFactory
DEFAULT
=
new
MetadataDecoderFactory
()
{
MetadataDecoderFactory
DEFAULT
=
new
MetadataDecoderFactory
()
{
@Override
public
boolean
supportsFormat
(
Format
format
)
{
String
mimeType
=
format
.
sampleMimeType
;
return
MimeTypes
.
APPLICATION_ID3
.
equals
(
mimeType
)
||
MimeTypes
.
APPLICATION_EMSG
.
equals
(
mimeType
)
||
MimeTypes
.
APPLICATION_SCTE35
.
equals
(
mimeType
);
}
@Override
public
MetadataDecoder
createDecoder
(
Format
format
)
{
switch
(
format
.
sampleMimeType
)
{
case
MimeTypes
.
APPLICATION_ID3
:
return
new
Id3Decoder
();
case
MimeTypes
.
APPLICATION_EMSG
:
return
new
EventMessageDecoder
();
case
MimeTypes
.
APPLICATION_SCTE35
:
return
new
SpliceInfoDecoder
();
default
:
throw
new
IllegalArgumentException
(
"Attempted to create decoder for unsupported format"
);
}
}
};
@Override
public
boolean
supportsFormat
(
Format
format
)
{
String
mimeType
=
format
.
sampleMimeType
;
return
MimeTypes
.
APPLICATION_ID3
.
equals
(
mimeType
)
||
MimeTypes
.
APPLICATION_EMSG
.
equals
(
mimeType
)
||
MimeTypes
.
APPLICATION_SCTE35
.
equals
(
mimeType
)
||
MimeTypes
.
APPLICATION_ICY
.
equals
(
mimeType
);
}
@Override
public
MetadataDecoder
createDecoder
(
Format
format
)
{
switch
(
format
.
sampleMimeType
)
{
case
MimeTypes
.
APPLICATION_ID3
:
return
new
Id3Decoder
();
case
MimeTypes
.
APPLICATION_EMSG
:
return
new
EventMessageDecoder
();
case
MimeTypes
.
APPLICATION_SCTE35
:
return
new
SpliceInfoDecoder
();
case
MimeTypes
.
APPLICATION_ICY
:
return
new
IcyDecoder
();
default
:
throw
new
IllegalArgumentException
(
"Attempted to create decoder for unsupported format"
);
}
}
};
}
}
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
android.support.annotation.Nullable
;
import
android.support.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
;
import
java.util.regex.Pattern
;
/** Decodes ICY stream information. */
public
final
class
IcyDecoder
implements
MetadataDecoder
{
private
static
final
String
TAG
=
"IcyDecoder"
;
private
static
final
Pattern
METADATA_ELEMENT
=
Pattern
.
compile
(
"(.+?)='(.+?)';"
);
private
static
final
String
STREAM_KEY_NAME
=
"streamtitle"
;
private
static
final
String
STREAM_KEY_URL
=
"streamurl"
;
@Override
@Nullable
@SuppressWarnings
(
"ByteBufferBackingArray"
)
public
Metadata
decode
(
MetadataInputBuffer
inputBuffer
)
{
ByteBuffer
buffer
=
inputBuffer
.
data
;
byte
[]
data
=
buffer
.
array
();
int
length
=
buffer
.
limit
();
return
decode
(
Util
.
fromUtf8Bytes
(
data
,
0
,
length
));
}
@Nullable
@VisibleForTesting
/* package */
Metadata
decode
(
String
metadata
)
{
String
name
=
null
;
String
url
=
null
;
int
index
=
0
;
Matcher
matcher
=
METADATA_ELEMENT
.
matcher
(
metadata
);
while
(
matcher
.
find
(
index
))
{
String
key
=
Util
.
toLowerInvariant
(
matcher
.
group
(
1
));
String
value
=
matcher
.
group
(
2
);
switch
(
key
)
{
case
STREAM_KEY_NAME:
name
=
value
;
break
;
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
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyHeaders.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
android.os.Parcel
;
import
android.os.Parcelable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
import
java.util.List
;
import
java.util.Map
;
/** ICY headers. */
public
final
class
IcyHeaders
implements
Metadata
.
Entry
{
public
static
final
String
REQUEST_HEADER_ENABLE_METADATA_NAME
=
"Icy-MetaData"
;
public
static
final
String
REQUEST_HEADER_ENABLE_METADATA_VALUE
=
"1"
;
private
static
final
String
TAG
=
"IcyHeaders"
;
private
static
final
String
RESPONSE_HEADER_BITRATE
=
"icy-br"
;
private
static
final
String
RESPONSE_HEADER_GENRE
=
"icy-genre"
;
private
static
final
String
RESPONSE_HEADER_NAME
=
"icy-name"
;
private
static
final
String
RESPONSE_HEADER_URL
=
"icy-url"
;
private
static
final
String
RESPONSE_HEADER_PUB
=
"icy-pub"
;
private
static
final
String
RESPONSE_HEADER_METADATA_INTERVAL
=
"icy-metaint"
;
/**
* Parses {@link IcyHeaders} from response headers.
*
* @param responseHeaders The response headers.
* @return The parsed {@link IcyHeaders}, or {@code null} if no ICY headers were present.
*/
@Nullable
public
static
IcyHeaders
parse
(
Map
<
String
,
List
<
String
>>
responseHeaders
)
{
boolean
icyHeadersPresent
=
false
;
int
bitrate
=
Format
.
NO_VALUE
;
String
genre
=
null
;
String
name
=
null
;
String
url
=
null
;
boolean
isPublic
=
false
;
int
metadataInterval
=
C
.
LENGTH_UNSET
;
List
<
String
>
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_BITRATE
);
if
(
headers
!=
null
)
{
String
bitrateHeader
=
headers
.
get
(
0
);
try
{
bitrate
=
Integer
.
parseInt
(
bitrateHeader
)
*
1000
;
if
(
bitrate
>
0
)
{
icyHeadersPresent
=
true
;
}
else
{
Log
.
w
(
TAG
,
"Invalid bitrate: "
+
bitrateHeader
);
bitrate
=
Format
.
NO_VALUE
;
}
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Invalid bitrate header: "
+
bitrateHeader
);
}
}
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_GENRE
);
if
(
headers
!=
null
)
{
genre
=
headers
.
get
(
0
);
icyHeadersPresent
=
true
;
}
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_NAME
);
if
(
headers
!=
null
)
{
name
=
headers
.
get
(
0
);
icyHeadersPresent
=
true
;
}
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_URL
);
if
(
headers
!=
null
)
{
url
=
headers
.
get
(
0
);
icyHeadersPresent
=
true
;
}
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_PUB
);
if
(
headers
!=
null
)
{
isPublic
=
headers
.
get
(
0
).
equals
(
"1"
);
icyHeadersPresent
=
true
;
}
headers
=
responseHeaders
.
get
(
RESPONSE_HEADER_METADATA_INTERVAL
);
if
(
headers
!=
null
)
{
String
metadataIntervalHeader
=
headers
.
get
(
0
);
try
{
metadataInterval
=
Integer
.
parseInt
(
metadataIntervalHeader
);
if
(
metadataInterval
>
0
)
{
icyHeadersPresent
=
true
;
}
else
{
Log
.
w
(
TAG
,
"Invalid metadata interval: "
+
metadataIntervalHeader
);
metadataInterval
=
C
.
LENGTH_UNSET
;
}
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Invalid metadata interval: "
+
metadataIntervalHeader
);
}
}
return
icyHeadersPresent
?
new
IcyHeaders
(
bitrate
,
genre
,
name
,
url
,
isPublic
,
metadataInterval
)
:
null
;
}
/**
* Bitrate in bits per second ({@code (icy-br * 1000)}), or {@link Format#NO_VALUE} if the header
* was not present.
*/
public
final
int
bitrate
;
/** The genre ({@code icy-genre}). */
@Nullable
public
final
String
genre
;
/** The stream name ({@code icy-name}). */
@Nullable
public
final
String
name
;
/** The URL of the radio station ({@code icy-url}). */
@Nullable
public
final
String
url
;
/**
* Whether the radio station is listed ({@code icy-pub}), or {@code false} if the header was not
* present.
*/
public
final
boolean
isPublic
;
/**
* The interval in bytes between metadata chunks ({@code icy-metaint}), or {@link C#LENGTH_UNSET}
* if the header was not present.
*/
public
final
int
metadataInterval
;
/**
* @param bitrate See {@link #bitrate}.
* @param genre See {@link #genre}.
* @param name See {@link #name See}.
* @param url See {@link #url}.
* @param isPublic See {@link #isPublic}.
* @param metadataInterval See {@link #metadataInterval}.
*/
public
IcyHeaders
(
int
bitrate
,
@Nullable
String
genre
,
@Nullable
String
name
,
@Nullable
String
url
,
boolean
isPublic
,
int
metadataInterval
)
{
Assertions
.
checkArgument
(
metadataInterval
==
C
.
LENGTH_UNSET
||
metadataInterval
>
0
);
this
.
bitrate
=
bitrate
;
this
.
genre
=
genre
;
this
.
name
=
name
;
this
.
url
=
url
;
this
.
isPublic
=
isPublic
;
this
.
metadataInterval
=
metadataInterval
;
}
/* package */
IcyHeaders
(
Parcel
in
)
{
bitrate
=
in
.
readInt
();
genre
=
in
.
readString
();
name
=
in
.
readString
();
url
=
in
.
readString
();
isPublic
=
Util
.
readBoolean
(
in
);
metadataInterval
=
in
.
readInt
();
}
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
getClass
()
!=
obj
.
getClass
())
{
return
false
;
}
IcyHeaders
other
=
(
IcyHeaders
)
obj
;
return
bitrate
==
other
.
bitrate
&&
Util
.
areEqual
(
genre
,
other
.
genre
)
&&
Util
.
areEqual
(
name
,
other
.
name
)
&&
Util
.
areEqual
(
url
,
other
.
url
)
&&
isPublic
==
other
.
isPublic
&&
metadataInterval
==
other
.
metadataInterval
;
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
result
=
31
*
result
+
bitrate
;
result
=
31
*
result
+
(
genre
!=
null
?
genre
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
name
!=
null
?
name
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
url
!=
null
?
url
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
isPublic
?
1
:
0
);
result
=
31
*
result
+
metadataInterval
;
return
result
;
}
@Override
public
String
toString
()
{
return
"IcyHeaders: name=\""
+
name
+
"\", genre=\""
+
genre
+
"\", bitrate="
+
bitrate
+
", metadataInterval="
+
metadataInterval
;
}
// Parcelable implementation.
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
writeInt
(
bitrate
);
dest
.
writeString
(
genre
);
dest
.
writeString
(
name
);
dest
.
writeString
(
url
);
Util
.
writeBoolean
(
dest
,
isPublic
);
dest
.
writeInt
(
metadataInterval
);
}
@Override
public
int
describeContents
()
{
return
0
;
}
public
static
final
Parcelable
.
Creator
<
IcyHeaders
>
CREATOR
=
new
Parcelable
.
Creator
<
IcyHeaders
>()
{
@Override
public
IcyHeaders
createFromParcel
(
Parcel
in
)
{
return
new
IcyHeaders
(
in
);
}
@Override
public
IcyHeaders
[]
newArray
(
int
size
)
{
return
new
IcyHeaders
[
size
];
}
};
}
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
android.os.Parcel
;
import
android.os.Parcelable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.util.Util
;
/** ICY in-stream information. */
public
final
class
IcyInfo
implements
Metadata
.
Entry
{
/** The stream title if present, or {@code null}. */
@Nullable
public
final
String
title
;
/** The stream title if present, or {@code null}. */
@Nullable
public
final
String
url
;
/**
* @param title See {@link #title}.
* @param url See {@link #url}.
*/
public
IcyInfo
(
@Nullable
String
title
,
@Nullable
String
url
)
{
this
.
title
=
title
;
this
.
url
=
url
;
}
/* package */
IcyInfo
(
Parcel
in
)
{
title
=
in
.
readString
();
url
=
in
.
readString
();
}
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
getClass
()
!=
obj
.
getClass
())
{
return
false
;
}
IcyInfo
other
=
(
IcyInfo
)
obj
;
return
Util
.
areEqual
(
title
,
other
.
title
)
&&
Util
.
areEqual
(
url
,
other
.
url
);
}
@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
;
}
@Override
public
String
toString
()
{
return
"ICY: title=\""
+
title
+
"\", url=\""
+
url
+
"\""
;
}
// Parcelable implementation.
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
writeString
(
title
);
dest
.
writeString
(
url
);
}
@Override
public
int
describeContents
()
{
return
0
;
}
public
static
final
Parcelable
.
Creator
<
IcyInfo
>
CREATOR
=
new
Parcelable
.
Creator
<
IcyInfo
>()
{
@Override
public
IcyInfo
createFromParcel
(
Parcel
in
)
{
return
new
IcyInfo
(
in
);
}
@Override
public
IcyInfo
[]
newArray
(
int
size
)
{
return
new
IcyInfo
[
size
];
}
};
}
library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
View file @
be2636c3
This diff is collapsed.
Click to expand it.
library/core/src/main/java/com/google/android/exoplayer2/source/IcyDataSource.java
0 → 100644
View file @
be2636c3
/*
* 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
;
import
android.net.Uri
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.TransferListener
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.Map
;
/**
* Splits ICY stream metadata out from a stream.
*
* <p>Note: {@link #open(DataSpec)} and {@link #close()} are not supported. This implementation is
* intended to wrap upstream {@link DataSource} instances that are opened and closed directly.
*/
/* package */
final
class
IcyDataSource
implements
DataSource
{
public
interface
Listener
{
/**
* Called when ICY stream metadata has been split from the stream.
*
* @param metadata The stream metadata in binary form.
*/
void
onIcyMetadata
(
ParsableByteArray
metadata
);
}
private
final
DataSource
upstream
;
private
final
int
metadataIntervalBytes
;
private
final
Listener
listener
;
private
final
byte
[]
metadataLengthByteHolder
;
private
int
bytesUntilMetadata
;
/**
* @param upstream The upstream {@link DataSource}.
* @param metadataIntervalBytes The interval between ICY stream metadata, in bytes.
* @param listener A listener to which stream metadata is delivered.
*/
public
IcyDataSource
(
DataSource
upstream
,
int
metadataIntervalBytes
,
Listener
listener
)
{
Assertions
.
checkArgument
(
metadataIntervalBytes
>
0
);
this
.
upstream
=
upstream
;
this
.
metadataIntervalBytes
=
metadataIntervalBytes
;
this
.
listener
=
listener
;
metadataLengthByteHolder
=
new
byte
[
1
];
bytesUntilMetadata
=
metadataIntervalBytes
;
}
@Override
public
void
addTransferListener
(
TransferListener
transferListener
)
{
upstream
.
addTransferListener
(
transferListener
);
}
@Override
public
long
open
(
DataSpec
dataSpec
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
@Override
public
int
read
(
byte
[]
buffer
,
int
offset
,
int
readLength
)
throws
IOException
{
if
(
bytesUntilMetadata
==
0
)
{
if
(
readMetadata
())
{
bytesUntilMetadata
=
metadataIntervalBytes
;
}
else
{
return
C
.
RESULT_END_OF_INPUT
;
}
}
int
bytesRead
=
upstream
.
read
(
buffer
,
offset
,
Math
.
min
(
bytesUntilMetadata
,
readLength
));
if
(
bytesRead
!=
C
.
RESULT_END_OF_INPUT
)
{
bytesUntilMetadata
-=
bytesRead
;
}
return
bytesRead
;
}
@Nullable
@Override
public
Uri
getUri
()
{
return
upstream
.
getUri
();
}
@Override
public
Map
<
String
,
List
<
String
>>
getResponseHeaders
()
{
return
upstream
.
getResponseHeaders
();
}
@Override
public
void
close
()
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
/**
* Reads an ICY stream metadata block, passing it to {@link #listener} unless the block is empty.
*
* @return True if the block was extracted, including if it's length byte indicated a length of
* zero. False if the end of the stream was reached.
* @throws IOException If an error occurs reading from the wrapped {@link DataSource}.
*/
private
boolean
readMetadata
()
throws
IOException
{
int
bytesRead
=
upstream
.
read
(
metadataLengthByteHolder
,
0
,
1
);
if
(
bytesRead
==
C
.
RESULT_END_OF_INPUT
)
{
return
false
;
}
int
metadataLength
=
(
metadataLengthByteHolder
[
0
]
&
0xFF
)
<<
4
;
if
(
metadataLength
==
0
)
{
return
true
;
}
int
offset
=
0
;
int
lengthRemaining
=
metadataLength
;
byte
[]
metadata
=
new
byte
[
metadataLength
];
while
(
lengthRemaining
>
0
)
{
bytesRead
=
upstream
.
read
(
metadata
,
offset
,
lengthRemaining
);
if
(
bytesRead
==
C
.
RESULT_END_OF_INPUT
)
{
return
false
;
}
offset
+=
bytesRead
;
lengthRemaining
-=
bytesRead
;
}
// Discard trailing zero bytes.
while
(
metadataLength
>
0
&&
metadata
[
metadataLength
-
1
]
==
0
)
{
metadataLength
--;
}
if
(
metadataLength
>
0
)
{
listener
.
onIcyMetadata
(
new
ParsableByteArray
(
metadata
,
metadataLength
));
}
return
true
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java
View file @
be2636c3
...
@@ -31,14 +31,15 @@ import java.util.Arrays;
...
@@ -31,14 +31,15 @@ import java.util.Arrays;
public
final
class
DataSpec
{
public
final
class
DataSpec
{
/**
/**
* The flags that apply to any request for data. Possible flag values are {@link #FLAG_ALLOW_GZIP}
* The flags that apply to any request for data. Possible flag values are {@link
* and {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}.
* #FLAG_ALLOW_GZIP}, {@link #FLAG_ALLOW_ICY_METADATA} and {@link
* #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}.
*/
*/
@Documented
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
@IntDef
(
flag
=
true
,
flag
=
true
,
value
=
{
FLAG_ALLOW_GZIP
,
FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN
})
value
=
{
FLAG_ALLOW_GZIP
,
FLAG_
ALLOW_ICY_METADATA
,
FLAG_
DONT_CACHE_IF_LENGTH_UNKNOWN
})
public
@interface
Flags
{}
public
@interface
Flags
{}
/**
/**
* Allows an underlying network stack to request that the server use gzip compression.
* Allows an underlying network stack to request that the server use gzip compression.
...
@@ -53,8 +54,11 @@ public final class DataSpec {
...
@@ -53,8 +54,11 @@ public final class DataSpec {
*/
*/
public
static
final
int
FLAG_ALLOW_GZIP
=
1
;
public
static
final
int
FLAG_ALLOW_GZIP
=
1
;
/** Allows an underlying network stack to request that the stream contain ICY metadata. */
public
static
final
int
FLAG_ALLOW_ICY_METADATA
=
1
<<
1
;
// 2
/** Prevents caching if the length cannot be resolved when the {@link DataSource} is opened. */
/** Prevents caching if the length cannot be resolved when the {@link DataSource} is opened. */
public
static
final
int
FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN
=
1
<<
1
;
// 2
public
static
final
int
FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN
=
1
<<
2
;
// 4
/**
/**
* The set of HTTP methods that are supported by ExoPlayer {@link HttpDataSource}s. One of {@link
* The set of HTTP methods that are supported by ExoPlayer {@link HttpDataSource}s. One of {@link
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
View file @
be2636c3
...
@@ -19,6 +19,7 @@ import android.net.Uri;
...
@@ -19,6 +19,7 @@ import android.net.Uri;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.upstream.DataSpec.HttpMethod
;
import
com.google.android.exoplayer2.upstream.DataSpec.HttpMethod
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Log
;
...
@@ -429,12 +430,20 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
...
@@ -429,12 +430,20 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
long
position
=
dataSpec
.
position
;
long
position
=
dataSpec
.
position
;
long
length
=
dataSpec
.
length
;
long
length
=
dataSpec
.
length
;
boolean
allowGzip
=
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_GZIP
);
boolean
allowGzip
=
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_GZIP
);
boolean
allowIcyMetadata
=
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_ALLOW_ICY_METADATA
);
if
(!
allowCrossProtocolRedirects
)
{
if
(!
allowCrossProtocolRedirects
)
{
// HttpURLConnection disallows cross-protocol redirects, but otherwise performs redirection
// HttpURLConnection disallows cross-protocol redirects, but otherwise performs redirection
// automatically. This is the behavior we want, so use it.
// automatically. This is the behavior we want, so use it.
return
makeConnection
(
return
makeConnection
(
url
,
httpMethod
,
httpBody
,
position
,
length
,
allowGzip
,
true
/* followRedirects */
);
url
,
httpMethod
,
httpBody
,
position
,
length
,
allowGzip
,
allowIcyMetadata
,
/* followRedirects= */
true
);
}
}
// We need to handle redirects ourselves to allow cross-protocol redirects.
// We need to handle redirects ourselves to allow cross-protocol redirects.
...
@@ -442,7 +451,14 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
...
@@ -442,7 +451,14 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
while
(
redirectCount
++
<=
MAX_REDIRECTS
)
{
while
(
redirectCount
++
<=
MAX_REDIRECTS
)
{
HttpURLConnection
connection
=
HttpURLConnection
connection
=
makeConnection
(
makeConnection
(
url
,
httpMethod
,
httpBody
,
position
,
length
,
allowGzip
,
false
/* followRedirects */
);
url
,
httpMethod
,
httpBody
,
position
,
length
,
allowGzip
,
allowIcyMetadata
,
/* followRedirects= */
false
);
int
responseCode
=
connection
.
getResponseCode
();
int
responseCode
=
connection
.
getResponseCode
();
String
location
=
connection
.
getHeaderField
(
"Location"
);
String
location
=
connection
.
getHeaderField
(
"Location"
);
if
((
httpMethod
==
DataSpec
.
HTTP_METHOD_GET
||
httpMethod
==
DataSpec
.
HTTP_METHOD_HEAD
)
if
((
httpMethod
==
DataSpec
.
HTTP_METHOD_GET
||
httpMethod
==
DataSpec
.
HTTP_METHOD_HEAD
)
...
@@ -482,6 +498,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
...
@@ -482,6 +498,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
* @param position The byte offset of the requested data.
* @param position The byte offset of the requested data.
* @param length The length of the requested data, or {@link C#LENGTH_UNSET}.
* @param length The length of the requested data, or {@link C#LENGTH_UNSET}.
* @param allowGzip Whether to allow the use of gzip.
* @param allowGzip Whether to allow the use of gzip.
* @param allowIcyMetadata Whether to allow ICY metadata.
* @param followRedirects Whether to follow redirects.
* @param followRedirects Whether to follow redirects.
*/
*/
private
HttpURLConnection
makeConnection
(
private
HttpURLConnection
makeConnection
(
...
@@ -491,6 +508,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
...
@@ -491,6 +508,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
long
position
,
long
position
,
long
length
,
long
length
,
boolean
allowGzip
,
boolean
allowGzip
,
boolean
allowIcyMetadata
,
boolean
followRedirects
)
boolean
followRedirects
)
throws
IOException
{
throws
IOException
{
HttpURLConnection
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
HttpURLConnection
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
...
@@ -515,6 +533,11 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
...
@@ -515,6 +533,11 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
if
(!
allowGzip
)
{
if
(!
allowGzip
)
{
connection
.
setRequestProperty
(
"Accept-Encoding"
,
"identity"
);
connection
.
setRequestProperty
(
"Accept-Encoding"
,
"identity"
);
}
}
if
(
allowIcyMetadata
)
{
connection
.
setRequestProperty
(
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_NAME
,
IcyHeaders
.
REQUEST_HEADER_ENABLE_METADATA_VALUE
);
}
connection
.
setInstanceFollowRedirects
(
followRedirects
);
connection
.
setInstanceFollowRedirects
(
followRedirects
);
connection
.
setDoOutput
(
httpBody
!=
null
);
connection
.
setDoOutput
(
httpBody
!=
null
);
connection
.
setRequestMethod
(
DataSpec
.
getStringForHttpMethod
(
httpMethod
));
connection
.
setRequestMethod
(
DataSpec
.
getStringForHttpMethod
(
httpMethod
));
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
View file @
be2636c3
...
@@ -92,6 +92,7 @@ public final class MimeTypes {
...
@@ -92,6 +92,7 @@ public final class MimeTypes {
public
static
final
String
APPLICATION_EMSG
=
BASE_TYPE_APPLICATION
+
"/x-emsg"
;
public
static
final
String
APPLICATION_EMSG
=
BASE_TYPE_APPLICATION
+
"/x-emsg"
;
public
static
final
String
APPLICATION_DVBSUBS
=
BASE_TYPE_APPLICATION
+
"/dvbsubs"
;
public
static
final
String
APPLICATION_DVBSUBS
=
BASE_TYPE_APPLICATION
+
"/dvbsubs"
;
public
static
final
String
APPLICATION_EXIF
=
BASE_TYPE_APPLICATION
+
"/x-exif"
;
public
static
final
String
APPLICATION_EXIF
=
BASE_TYPE_APPLICATION
+
"/x-exif"
;
public
static
final
String
APPLICATION_ICY
=
BASE_TYPE_APPLICATION
+
"/x-icy"
;
private
static
final
ArrayList
<
CustomMimeType
>
customMimeTypes
=
new
ArrayList
<>();
private
static
final
ArrayList
<
CustomMimeType
>
customMimeTypes
=
new
ArrayList
<>();
...
...
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.RobolectricTestRunner
;
/** Test for {@link IcyDecoder}. */
@RunWith
(
RobolectricTestRunner
.
class
)
public
final
class
IcyDecoderTest
{
@Test
public
void
decode
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test title';StreamURL='test_url';"
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
@Test
public
void
decode_titleOnly
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test title';"
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
url
).
isNull
();
}
@Test
public
void
decode_semiColonInTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test; title';StreamURL='test_url';"
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test; title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
@Test
public
void
decode_quoteInTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test' title';StreamURL='test_url';"
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test' title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
@Test
public
void
decode_notIcy
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"NotIcyData"
);
assertThat
(
metadata
).
isNull
();
}
}
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyHeadersTest.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.os.Parcel
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.RobolectricTestRunner
;
/** Test for {@link IcyHeaders}. */
@RunWith
(
RobolectricTestRunner
.
class
)
public
final
class
IcyHeadersTest
{
@Test
public
void
parcelEquals
()
{
IcyHeaders
icyHeaders
=
new
IcyHeaders
(
/* bitrate= */
1234
,
"genre"
,
"name"
,
"url"
,
/* isPublic= */
true
,
/* metadataInterval= */
5678
);
// Write to parcel.
Parcel
parcel
=
Parcel
.
obtain
();
icyHeaders
.
writeToParcel
(
parcel
,
0
);
// Create from parcel.
parcel
.
setDataPosition
(
0
);
IcyHeaders
fromParcelIcyHeaders
=
IcyHeaders
.
CREATOR
.
createFromParcel
(
parcel
);
// Assert equals.
assertThat
(
fromParcelIcyHeaders
).
isEqualTo
(
icyHeaders
);
}
}
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java
0 → 100644
View file @
be2636c3
/*
* 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
.
metadata
.
icy
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.os.Parcel
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.RobolectricTestRunner
;
/** Test for {@link IcyInfo}. */
@RunWith
(
RobolectricTestRunner
.
class
)
public
final
class
IcyStreamInfoTest
{
@Test
public
void
parcelEquals
()
{
IcyInfo
streamInfo
=
new
IcyInfo
(
"name"
,
"url"
);
// Write to parcel.
Parcel
parcel
=
Parcel
.
obtain
();
streamInfo
.
writeToParcel
(
parcel
,
0
);
// Create from parcel.
parcel
.
setDataPosition
(
0
);
IcyInfo
fromParcelStreamInfo
=
IcyInfo
.
CREATOR
.
createFromParcel
(
parcel
);
// Assert equals.
assertThat
(
fromParcelStreamInfo
).
isEqualTo
(
streamInfo
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment