metadata.java

来自「java语言开发的P2P流媒体系统」· Java 代码 · 共 516 行

JAVA
516
字号
/* 
 * P2P-Radio - Peer to peer streaming system
 * Project homepage: http://p2p-radio.sourceforge.net/
 * Copyright (C) 2003-2004 Michael Kaufmann <hallo@michael-kaufmann.ch>
 * 
 * ---------------------------------------------------------------------------
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * ---------------------------------------------------------------------------
 */

package p2pradio;

import p2pradio.logging.Logger;
import java.io.*;
import java.util.*;


/**
 * Contains all metadata of a stream. 
 *
 * @author Michael Kaufmann
 */
public class Metadata implements Cloneable
{
	//Send these parameters from the server directly to the client
	//Sent once through AcceptPacket upon initial connection
	public static final String CONTENT_TYPE = "ContentType"; //$NON-NLS-1$         
	public static final String STATION_NAME = "StationName"; //$NON-NLS-1$         
	public static final String STATION_URL = "StationURL"; //$NON-NLS-1$          
	public static final String STATION_GENRE = "Genre"; //$NON-NLS-1$              
	public static final String STATION_DESCRIPTION = "Description"; //$NON-NLS-1$  
	public static final String HTTP_HEADERS = "HttpHeaders"; //$NON-NLS-1$
	public static final String BYTERATE = "Byterate"; //$NON-NLS-1$
	
	//The client and server keep these parameters private (not sent).  
	public static final String STATION_PUBLIC = "Public"; //$NON-NLS-1$			
	public static final String AVERAGE_BYTERATE = "AverageByterate"; //$NON-NLS-1$
	public static final String SERVER = "Server"; //$NON-NLS-1$                    
	public static final String SERVER_PROTOCOL = "ServerProtocol"; //$NON-NLS-1$   
	
	//These parameters are sent periodically through the network (p2p and multicast+)
	//They are also sent in the AcceptPacket upon initial connection
	public static final String SONG_TITLE = "SongTitle"; //$NON-NLS-1$
	public static final String SONG_URL = "SongURL"; //$NON-NLS-1$
	
	
			
	public static final String CONTENT_TYPE_DEFAULT = "content/unknown"; //$NON-NLS-1$
	public static final String SERVER_DEFAULT = Radio.NameSlashVersion; //$NON-NLS-1$
	public static final String SERVER_PROTOCOL_DEFAULT = "HTTP"; //$NON-NLS-1$
	public static final String STATION_NAME_DEFAULT = ""; //$NON-NLS-1$
	public static final String STATION_URL_DEFAULT = ""; //$NON-NLS-1$
	public static final String STATION_GENRE_DEFAULT = ""; //$NON-NLS-1$
	public static final String STATION_DESCRIPTION_DEFAULT = ""; //$NON-NLS-1$
	public static final String STATION_PUBLIC_DEFAULT = "1"; //$NON-NLS-1$
	public static final String SONG_TITLE_DEFAULT = ""; //$NON-NLS-1$
	public static final String SONG_URL_DEFAULT = ""; //$NON-NLS-1$
	public static final String HTTP_HEADERS_DEFAULT = ""; //$NON-NLS-1$
	public static final String BYTERATE_DEFAULT = "0"; //$NON-NLS-1$
	public static final String AVERAGE_BYTERATE_DEFAULT = "0"; //$NON-NLS-1$
		
	protected Properties metadata;
	
	// "Cache" f黵 die Methode toByteArray()
	byte[] byteArray;
	
	
	/**
	 * Creates a new metadata object, filled with default values.
	 */
	public Metadata()
	{
		init();
	}
	
	/**
	 * Creates a new metadata object that reads its metadata from a stream.
	 *
	 * @param inputStream The input stream to read the metadata from
	 */
	public Metadata(InputStream inputStream)
	{
		init();
		
	    load(inputStream);
		
		// Schauen, ob die Byterate ein Integer-wert ist
		try
		{
			getByterate();
			getAverageByterate();
		}
		catch (NumberFormatException e)
		{
			throw new IllegalArgumentException(Messages.getString("Metadata.INVALID_BYTERATE")); //$NON-NLS-1$
		}
	}
	public void load(InputStream inputStream)
	{
		try {
			metadata.load(inputStream);
		}
		catch (IOException e)
		{
			throw new IllegalArgumentException(Messages.getString("Metadata.COULD_NOT_READ_METADATA")); //$NON-NLS-1$
		}
	}
	
	protected void init()
	{
		metadata = new Properties();
		metadata.setProperty(CONTENT_TYPE, CONTENT_TYPE_DEFAULT);
		metadata.setProperty(SERVER, SERVER_DEFAULT);
		metadata.setProperty(SERVER_PROTOCOL, SERVER_PROTOCOL_DEFAULT);
		metadata.setProperty(STATION_NAME, STATION_NAME_DEFAULT);
		metadata.setProperty(STATION_URL, STATION_URL_DEFAULT);
		metadata.setProperty(STATION_GENRE, STATION_GENRE_DEFAULT);
		metadata.setProperty(STATION_DESCRIPTION, STATION_DESCRIPTION_DEFAULT);
		metadata.setProperty(STATION_PUBLIC, STATION_PUBLIC_DEFAULT);
		metadata.setProperty(SONG_TITLE, SONG_TITLE_DEFAULT);
		metadata.setProperty(SONG_URL, SONG_URL_DEFAULT);
		metadata.setProperty(HTTP_HEADERS, HTTP_HEADERS_DEFAULT);
		metadata.setProperty(BYTERATE, BYTERATE_DEFAULT);
		metadata.setProperty(AVERAGE_BYTERATE, AVERAGE_BYTERATE_DEFAULT);
	}

	public synchronized void setContentType(String contentType)
	{
		byteArray = null;
		metadata.setProperty(CONTENT_TYPE, contentType);
	}
	
	public synchronized String getContentType()
	{
		return metadata.getProperty(CONTENT_TYPE);
	}
	
	public synchronized void setServer(String server)
	{
		byteArray = null;
		metadata.setProperty(SERVER, server + " & " + Radio.NameSlashVersion); //$NON-NLS-1$
	}
	
	public synchronized String getServer()
	{
		return metadata.getProperty(SERVER);
	}
	
	public synchronized void setServerProtocol(String serverProtocol)
	{
		byteArray = null;
		metadata.setProperty(SERVER_PROTOCOL, serverProtocol);
	}
	
	public synchronized String getServerProtocol()
	{
		return metadata.getProperty(SERVER_PROTOCOL);
	}

	public synchronized void setStationName(String stationName)
	{
		byteArray = null;
		metadata.setProperty(STATION_NAME, stationName);
		handleSameStationNameAndDescription();
	}
	
	public synchronized String getStationName()
	{
		return metadata.getProperty(STATION_NAME);
	}
	
	public synchronized void setStationURL(String stationURL)
	{
		byteArray = null;
		metadata.setProperty(STATION_URL, stationURL);
		handleSameStationAndSongURL();
	}
	
	public synchronized String getStationURL()
	{
		return metadata.getProperty(STATION_URL);
	}
	
	public synchronized void setGenre(String stationGenre)
	{
		byteArray = null;
		metadata.setProperty(STATION_GENRE, stationGenre);
	}
	
	public synchronized String getGenre()
	{
		return metadata.getProperty(STATION_GENRE); 
	}
	
	public synchronized void setDescription(String stationDescription)
	{
		byteArray = null;
		metadata.setProperty(STATION_DESCRIPTION, stationDescription);
		handleSameStationNameAndDescription();
	}
	
	public synchronized String getDescription()
	{
		return metadata.getProperty(STATION_DESCRIPTION);
	}
	
	public synchronized void setPublic(boolean isPublic)
	{
		byteArray = null;
		
		if (isPublic)
		{
			metadata.setProperty(STATION_PUBLIC, "1"); //$NON-NLS-1$
		}
		else
		{
			metadata.setProperty(STATION_PUBLIC, "0"); //$NON-NLS-1$
		}
	}
	
	public boolean isPublic()
	{
		return metadata.getProperty(STATION_PUBLIC).equals("1"); //$NON-NLS-1$
	}
	
	public synchronized void setSongTitle(String songTitle)
	{
		byteArray = null;
		metadata.setProperty(SONG_TITLE, songTitle);
	}
	
	public synchronized String getSongTitle()
	{
		return metadata.getProperty(SONG_TITLE);
	}
	
	public synchronized void setSongURL(String songURL)
	{
		byteArray = null;
		metadata.setProperty(SONG_URL, songURL);
		handleSameStationAndSongURL();
	}
	
	public synchronized String getSongURL()
	{
		return metadata.getProperty(SONG_URL);
	}
	
	public synchronized void setHttpHeaders(String httpHeaders)
	{
		byteArray = null;
		metadata.setProperty(HTTP_HEADERS, httpHeaders);
	}
	
	public synchronized String getHttpHeaders()
	{
		return metadata.getProperty(HTTP_HEADERS);
	}

	public synchronized void setByterate(int byteRate)
	{
		if (byteRate < 0)
		{
			throw new IllegalArgumentException();
		}
		
		byteArray = null;
		metadata.setProperty(BYTERATE, Integer.toString(byteRate));
	}
	
	public synchronized int getByterate() throws NumberFormatException
	{
		return Integer.parseInt(metadata.getProperty(BYTERATE));
	}
	
	public synchronized void setAverageByterate(int averageByteRate)
	{
		if (averageByteRate < 0)
		{
			throw new IllegalArgumentException();
		}
		
		byteArray = null;
		metadata.setProperty(AVERAGE_BYTERATE, Integer.toString(averageByteRate));
	}
	
	public synchronized int getAverageByterate() throws NumberFormatException
	{
		return Integer.parseInt(metadata.getProperty(AVERAGE_BYTERATE));
	}
	
	public synchronized boolean isICYStream()
	{
		return getServerProtocol().toUpperCase().equals("ICY"); //$NON-NLS-1$
	}
	
	/**
	 * Adds a user-defined key/value-pair to the metadata.
	 */
	/*
	private synchronized void setProperty(String key, String value)
	{
		byteArray = null;
		metadata.setProperty(key, value);
	}
	*/
	
	/**
	 * Returns the value of the specified metadata key.
	 */
	/*
	private synchronized String getProperty(String key)
	{
		return metadata.getProperty(key);
	}
	*/
	
	/**
	 * Returns an enumeration of all metadata keys.
	 */
	/*public synchronized Enumeration propertyNames()
	{
		return metadata.propertyNames();
	}*/
	
	public synchronized String toHttpHeaders(String prefix, boolean includeMetaInt)
	{
		String headers = null; //$NON-NLS-1$
		
		boolean isICY = prefix.toLowerCase().equals("icy-"); //$NON-NLS-1$
		
		if (isICY)
		{
			headers = getHeader(headers, prefix, "notice1", "<BR>This stream requires a media player like Winamp, XMMS or Zinf<BR>"); //$NON-NLS-1$ //$NON-NLS-2$
			headers = getHeader(headers, prefix, "notice2", getServer() + "<BR>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}
		
		headers = getHeader(headers, prefix, "name", getStationName()); //$NON-NLS-1$
		headers = getHeader(headers, prefix, "url", getStationURL()); //$NON-NLS-1$
		headers = getHeader(headers, prefix, "genre", getGenre()); //$NON-NLS-1$
		headers = getHeader(headers, prefix, "description", getDescription()); //$NON-NLS-1$
		
		String publicString;
		String privateString;
		
		if (isPublic())
		{
			publicString = "1"; //$NON-NLS-1$
			privateString = "0"; //$NON-NLS-1$
		}
		else
		{
			publicString = "0"; //$NON-NLS-1$
			privateString ="1"; //$NON-NLS-1$
		}
		
		if (isICY)
		{
			headers = getHeader(headers, prefix, "pub", publicString); //$NON-NLS-1$
		}
		else
		{
			headers = getHeader(headers, prefix, "public", publicString); //$NON-NLS-1$			
			headers = getHeader(headers, prefix, "private", privateString); //$NON-NLS-1$
		}
		
		if (includeMetaInt)
		{
			headers = getHeader(headers, prefix, "metaint", Integer.toString(p2pradio.players.HttpPlayerServer.ICY_METADATA_INTERVAL)); //$NON-NLS-1$
		}
		
		if (getByterate() != 0)
		{
			if (isICY)
			{
				headers = getHeader(headers, prefix, "br", Integer.toString(getByterate() / 125)); //$NON-NLS-1$
			}
			else
			{
				headers = getHeader(headers, prefix, "bitrate", Integer.toString(getByterate() / 125)); //$NON-NLS-1$				
			}
		}
		
		return headers;				
	}
	
	private String getHeader(String headers, String prefix, String key, String value)
	{
		if (value.length() != 0)
		{
			String newHeader = prefix + key + ": " + value; //$NON-NLS-1$
			
			if (headers == null)
			{
				return newHeader;
			}
			else
			{
				return headers + "\r\n" + newHeader; //$NON-NLS-1$
			}
		}
		else
		{
			return headers;
		}
	}
	
	/**
	 * Writes all key/value-pairs of this metadata object into a byte array.
	 * It can be read later with {@link #Metadata(InputStream)} using a {@link java.io.ByteArrayInputStream}.
	 */
	public synchronized byte[] toByteArray()
	{
		if (byteArray == null)
		{
			// Metadaten in einen ByteArrayOutputStream speichern
			ByteArrayOutputStream metadataStream = new ByteArrayOutputStream();
			Properties urltitle = new Properties();
			urltitle.setProperty(SONG_TITLE, getSongTitle());
			urltitle.setProperty(SONG_URL, getSongURL());
			try
			{
				urltitle.store(metadataStream, "Metadata"); //$NON-NLS-1$
			}
			catch (IOException e)
			{
				// Sollte eigentlich nicht vorkommen
				Logger.severe("Metadata", "INTERNAL_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
			}
		
			// In ein Byte-Array umwandeln
			byteArray = metadataStream.toByteArray();
		}
		
		return byteArray;
	}
	
	public String toString()
	{
		return metadata.toString();
	}
	
	/**
	 * Checks if two metadata objects contain identical metadata.
	 */
	public boolean equals(Object other)
	{
		return metadata.equals(((Metadata)other).metadata);
	}
	
	/**
	 * Creates a clone with identical metadata.
	 */
	public Object clone()
	{
		Object object = null;
		try
		{
			object = super.clone();
		}
		catch (CloneNotSupportedException e)
		{
		}
		
		Metadata metadataObject = (Metadata)object;
		metadataObject.metadata = (Properties)metadata.clone();
		
		return metadataObject;
	}
	
	public void setProperties(Properties metadata)
	{
		this.metadata = metadata;
	}
	public Properties getProperties()
	{
		return metadata;
	}
	
	private synchronized void handleSameStationAndSongURL()
	{
		// Es gibt einige Shoutcast-Sender, die als Song-URL
		// einfach die Sender-URL angeben. In diesem Fall
		// die Song-URL einfach ignorieren
		//
		// Achtung: Die Song-URL nur setzen, falls sie nicht schon die Default-URL ist,
		// zum Beispiel eine leere Zeichenfolge (Stack-躡erlauf!)
		if (getStationURL().equals(getSongURL()) && !getSongURL().equals(SONG_URL_DEFAULT))
		{
			setSongURL(SONG_URL_DEFAULT);
		}
	}
	
	private synchronized void handleSameStationNameAndDescription()
	{
		// Oddsock DSP macht keinen Unterschied zwischen dem Sendernamen
		// und der Beschreibung. Falls beide gleich sind die Beschreibung
		// entfernen
		if (getStationName().equals(getDescription()) && !getDescription().equals(STATION_DESCRIPTION_DEFAULT))
		{
			setDescription(STATION_DESCRIPTION_DEFAULT);
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?