javazoom.spi.mpeg.sampled.file.tag
public class IcyInputStream extends java.io.BufferedInputStream implements MP3MetadataParser
The deal with metaint: Icy streams don't try to put
tags between MP3 frames the way that ID3 does. Instead, it
requires the client to strip metadata from the stream before
it hits the decoder. You get an
icy-metaint
name/val in the beginning of the
stream iff you sent "Icy-Metadata" with value "1" in the
request headers (SimpleMP3DataSource does this if the
"parseStreamMetadata" boolean is true). If this is the case
then the value of icy-metaint is the amount of real data
between metadata blocks. Each block begins with an int
indicating how much metadata there is -- the block is this
value times 16 (it can be, and often is, 0).
Originally thought that "icy" implied Icecast, but this is completely wrong -- real Icecast servers, found through www.icecast.net and typified by URLs with a trailing directory (like CalArts School of Music - http://65.165.174.100:8000/som) do not have the "ICY 200 OK" magic string or any of the CRLF-separated headers. Apparently, "icy" means "Shoutcast". Yep, that's weird.
Modifier and Type | Field and Description |
---|---|
protected int |
bytesUntilNextMetadata
how many bytes of real data remain before the next
block of metadata.
|
protected byte[] |
crlfBuffer
Buffer for readCRLF line...
|
static boolean |
DEBUG |
protected static java.lang.String |
INLINE_TAG_SEPARATORS
inline tags are delimited by ';', also filter out
null bytes
|
protected int |
metaint
value of the "metaint" tag, which tells us how many bytes
of real data are between the metadata tags.
|
Constructor and Description |
---|
IcyInputStream(java.io.InputStream in)
Reads the initial headers of the stream and adds
tags appropriatly.
|
IcyInputStream(java.io.InputStream in,
java.lang.String metaIntString)
IcyInputStream constructor for know meta-interval (Icecast 2)
|
Modifier and Type | Method and Description |
---|---|
protected void |
addTag(IcyTag tag)
adds the tag to the HashMap of tags we have encountered
either in-stream or as headers, replacing any previous
tag with this name.
|
void |
addTagParseListener(TagParseListener tpl)
Adds a TagParseListener to be notified when this stream
parses MP3Tags.
|
MP3Tag |
getTag(java.lang.String tagName)
Get the named tag from the HashMap of headers and
in-line tags.
|
java.util.HashMap |
getTagHash()
Returns a HashMap of all headers and in-stream tags
parsed so far.
|
MP3Tag[] |
getTags()
Get all tags (headers or in-stream) encountered thus far.
|
static void |
main(java.lang.String[] args)
Quickie unit-test.
|
protected void |
parseInlineIcyTags(byte[] tagBlock)
Parse metadata from an in-stream "block" of bytes, add
a tag for each one.
|
int |
read()
Reads and returns a single byte.
|
int |
read(byte[] buf)
trivial
return read (buf, 0, buf.length) |
int |
read(byte[] buf,
int offset,
int length)
Reads a block of bytes.
|
protected java.lang.String |
readCRLFLine()
Read everything up to the next CRLF, return it as
a String.
|
protected void |
readInitialHeaders()
Assuming we're at the top of the stream, read lines one
by one until we hit a completely blank \r\n.
|
protected void |
readMetadata()
Read the next segment of metadata.
|
void |
removeTagParseListener(TagParseListener tpl)
Removes a TagParseListener, so it won't be notified when
this stream parses MP3Tags.
|
public static boolean DEBUG
protected static final java.lang.String INLINE_TAG_SEPARATORS
protected byte[] crlfBuffer
protected int metaint
protected int bytesUntilNextMetadata
public IcyInputStream(java.io.InputStream in) throws java.io.IOException
icy-metaint
header is found.java.io.IOException
public IcyInputStream(java.io.InputStream in, java.lang.String metaIntString) throws java.io.IOException
in
- metaint
- java.io.IOException
protected void readInitialHeaders() throws java.io.IOException
java.io.IOException
protected java.lang.String readCRLFLine() throws java.io.IOException
java.io.IOException
public int read() throws java.io.IOException
read
in class java.io.BufferedInputStream
java.io.IOException
public int read(byte[] buf, int offset, int length) throws java.io.IOException
bytesUntilNextMetadata < length
read
in class java.io.BufferedInputStream
java.io.IOException
public int read(byte[] buf) throws java.io.IOException
return read (buf, 0, buf.length)
read
in class java.io.FilterInputStream
java.io.IOException
protected void readMetadata() throws java.io.IOException
java.io.IOException
protected void parseInlineIcyTags(byte[] tagBlock)
Hilariously, the inline data format is totally different than the top-of-stream header. For example, here's a block I saw on "Final Fantasy Radio":
StreamTitle='Final Fantasy 8 - Nobuo Uematsu - Blue Fields';StreamUrl='';In other words:
protected void addTag(IcyTag tag)
public MP3Tag getTag(java.lang.String tagName)
public MP3Tag[] getTags()
getTags
in interface MP3MetadataParser
public java.util.HashMap getTagHash()
public void addTagParseListener(TagParseListener tpl)
addTagParseListener
in interface MP3MetadataParser
public void removeTagParseListener(TagParseListener tpl)
removeTagParseListener
in interface MP3MetadataParser
public static void main(java.lang.String[] args)
JavaZOOM 1999-2005