⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpplayerserver.java

📁 java语言开发的P2P流媒体系统
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* Stream-2-Stream - Peer to peer television and radio
 * October 13, 2005 - This file has been modified from the original P2P-Radio source
 * Project homepage: http://s2s.sourceforge.net/
 * Copyright (C) 2005-2006 Jason Hooks
 */

/* 
 * 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.players;

import p2pradio.*;
import p2pradio.event.*;
import p2pradio.io.*;
import p2pradio.logging.Logger;
import p2pradio.sources.ShoutcastMetadata;
import java.io.*;
import java.net.*;


/**
 * Provides a Http/Shoutcast/Icecast compatible streaming server.
 * 
 * @author Michael Kaufmann
 */	 
public class HttpPlayerServer extends Player implements
  HeaderChangedListener, MetadataChangedListener,
  DataLeapListener, WaitForLeadListener
{
	private HttpPlayer parent;
	private ListenBuffer buffer;
	private Socket socket;
	
	// Puffer f黵 die Shoutcast-Metadaten
	private byte[] shoutcastMetadata = new byte[4080];
	
	// Anzahl Sekunden des Stroms, die bei Verbindungsaufbau
	// sofort an den Media-Player gesendet werden sollen
	// Muss nat黵lich kleiner sein als Buffer.MAX_TIME_IN_BUFFER!
	public static final int MILLISECONDS_IN_MEDIAPLAYER_BUFFER = 10000;
	
	// Hat sich der Header ge鋘dert?
	private boolean headerHasChanged = false;

	// Haben sich die Metadaten ge鋘dert?
	private boolean metadataHasChanged = true;

	// Shoutcast-Metadaten-Intervall
	public static final int ICY_METADATA_INTERVAL = 8192;
	private long startTime;								   //Start Time (in milliseconds)
	private long Time_Server_Has_Been_Running_At_Startup;  //The time the server has been running when we start P2PRadio (in milliseconds)
															//Will always be 0 if we are the server
	private long Server_Running_Minus_Start_Time;
	private boolean shutdown;
	public HttpPlayerServer(HttpPlayer parent, ListenBuffer buffer, Socket socket)
	{
		super(buffer, Messages.getString("HttpPlayerServer.THREAD_NAME")); //$NON-NLS-1$
		startTime = parent.getStartTime();
		Time_Server_Has_Been_Running_At_Startup = parent.Get_Time_Server_Has_Been_Running_At_Startup();
		Server_Running_Minus_Start_Time = Time_Server_Has_Been_Running_At_Startup - startTime;
		
		this.parent = parent;//jhooks - \/
		this.buffer = buffer;//Buffer appears to be reading data from the p2pradio server
		this.socket = socket;//Socket appears to be acting as a shoutcast server to a local player
							 //That is, this socket is the end of the line for the stream, you watch it in your player
		shutdown = false;
	}

	public void headerChanged(HeaderChangedEvent e)
	{
		headerHasChanged = true;
	}
	
	public void metadataChanged(MetadataChangedEvent e)
	{
		metadataHasChanged = true;
	}
	
	public void dataLeap(DataLeapEvent e)
	{
		// Was tun?	
	}
	
	public void waitForLead(WaitForLeadEvent e)
	{
		// Nicht warten	
	}
	
	/**
	 * Returns the MIME type that this player can handle: <code>audio/mpeg</code>. 
	 */
	public String getMIMEType()
	{
		return "*/*"; //$NON-NLS-1$
	}
	
	public void run()
	{
		Logger.finer("HttpPlayerServer", "HttpPlayerServer.THREAD_RUNNING"); //$NON-NLS-1$ //$NON-NLS-2$
		
		// Der Puffer soll uns laufend informieren
		buffer.addHeaderChangedListener(this);
		buffer.addMetadataChangedListener(this);
		buffer.addDataLeapListener(this);
		buffer.addWaitForLeadListener(this);

		HttpInputStream inputStream = null;
		OutputStream outputStream = null;
		BufferedReader reader = null;
		NewLineWriter writer = null;
		long lag = 0;
		long timeStamp = 0;
		FileOutputStream outgoingStreamDump = null;
		if (shutdown)
			return;
		
		try
		{
			inputStream = new HttpInputStream(new DataInputStream(socket.getInputStream()));
			outputStream = new BufferedOutputStream(socket.getOutputStream());
			reader = new BufferedReader(new InputStreamReader(inputStream));
			writer = new NewLineWriter(new OutputStreamWriter(outputStream), NewLineWriter.CRLF);
			
			// Die Anfrage lesen
			// Beispiel: "GET /stream/123 HTTP/1.0"
			// Die URL wird dabei nicht beachtet
			
			String line = reader.readLine();
			if (shutdown)
				return;
			if (line == null)
			{
				Logger.finer("HttpPlayerServer", "HttpPlayerServer.MEDIA_PLAYER_DISCONNECTED"); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}

			line = line.trim();
					
			int firstSpacePos = line.indexOf(" "); //$NON-NLS-1$
			if (firstSpacePos == -1)
			{
				// Ung黮tige Anfrage
				Logger.fine("HttpPlayerServer", "INVALID_REQUEST"); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}
			
			String method = line.substring(0, firstSpacePos).toLowerCase();
			
			if (!(method.equals("get") || method.equals("head"))) //$NON-NLS-1$ //$NON-NLS-2$
			{
				// Ung黮tige Anfrage
				Logger.fine("HttpPlayerServer", "INVALID_REQUEST"); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}
		
			int secondSpacePos = line.indexOf(" ", firstSpacePos+1); //$NON-NLS-1$
			if (secondSpacePos == -1)
			{
				// Kein zweites Leerzeichen
				Logger.fine("HttpPlayerServer", "INVALID_REQUEST"); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}
			
			
			String requestURL = line.substring(firstSpacePos+1, secondSpacePos).toLowerCase();
			if (requestURL.length() == 0)
			{
				// Ung黮tige URL
				Logger.fine("HttpPlayerServer", "INVALID_REQUEST"); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}
			
			String protocol = line.substring(secondSpacePos+1, line.length()).toLowerCase();
			protocol = protocol.trim();
				
			// Version entfernen (statt "HTTP/1.0" nur "HTTP")
			int slashPos = protocol.indexOf("/"); //$NON-NLS-1$
			if (slashPos != -1)
			{
				protocol = protocol.substring(0, slashPos);
			}
			
			if (!protocol.equals("http")) //$NON-NLS-1$
			{
				// Unbekanntes Protokoll
				Logger.fine("HttpPlayerServer", "UNKNOWN_PROTOCOL", protocol); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}
			
			if (shutdown)
				return;
			// Die Anfrage ist soweit in Ordnung
			// Die Metadaten einlesen und schauen,
			// ob "icy-metadata:1" vorkommt
			
			boolean icyMetadataFound = false;
						 
			while (!shutdown)
			{
				line = reader.readLine();
				if (shutdown)
					return;
				if ((line == null) || (line.length() == 0))
				{
					break;
				}
					
				int colonPos = line.indexOf(":"); //$NON-NLS-1$
					
				if (colonPos == -1)
				{
					// Kein Doppelpunkt kommt vor - es kann keine
					// Headerzeile mehr sein
					return;
				}
			
				String key = line.substring(0, colonPos);
				String value = line.substring(colonPos+1, line.length());
				key = key.trim();
				value = value.trim();
				
				String keyLowerCase = key.toLowerCase();
						
				if (keyLowerCase.equals("icy-metadata")) //$NON-NLS-1$
				{
					if (value.equals("1")) //$NON-NLS-1$
					{
						icyMetadataFound = true;
					}
				}
				else if (keyLowerCase.equals("user-agent")) //$NON-NLS-1$
				{
					Logger.finer("HttpPlayerServer", "ACCESS_BY", value); //$NON-NLS-1$ //$NON-NLS-2$
					
					// Pr黤en, ob mit einer alten Winamp-Version
					// auf einen NSV-Strom zugegriffen wird
					if (buffer.getMetadata().getContentType().toLowerCase().equals("video/nsv")) //$NON-NLS-1$
					{
						if (value.startsWith("WinampMPEG/2.")) //$NON-NLS-1$
						{
							// Es wird mindestens Winamp 2.9x ben鰐igt
							if (value.length() >= 14)
							{
								if (!value.substring(13, 14).equals("9")) //$NON-NLS-1$
								{
									Logger.warning("HttpPlayerServer", "HttpPlayerServer.NSV_TOO_OLD_WINAMP_VERSION"); //$NON-NLS-1$ //$NON-NLS-2$
									
									writer.writeln("ICY 401 " + Messages.getString("HttpPlayerServer.NSV_TOO_OLD_WINAMP_VERSION")); //$NON-NLS-1$ //$NON-NLS-2$
									writer.writeln();
									writer.flush();
									return;
								}
							}
						}
					}
				}
			}
			
			if (shutdown)
				return;
			// Anfrage bearbeiten 
			
			if (method.equals("get")) //$NON-NLS-1$
			{
				if (requestURL.equals(HttpPlayer.PLAYLIST_NAME))
				{
					// Ein Browser, der die Playlist will
					
					writer.writeln("HTTP/1.0 200 OK"); //$NON-NLS-1$
					writer.writeln("Content-type: audio/x-scpls"); //$NON-NLS-1$
					writer.writeln();
					
					writer.setNewLineMark(NewLineWriter.LF);					
					writer.writeln("[playlist]"); //$NON-NLS-1$
					writer.writeln("numberofentries=1"); //$NON-NLS-1$
					writer.writeln("File1=" + parent.getStreamURL()); //$NON-NLS-1$
					writer.writeln("Title1=" + buffer.getMetadata().getStationName()); //$NON-NLS-1$
					
					writer.writeln("Length1=-1"); //$NON-NLS-1$
					writer.writeln("Version=2"); //$NON-NLS-1$
					if (shutdown)
						return;	
					writer.flush();

					return;
				}
				else // if (requestURL.equals(ShoutcastPlayer.STREAM_NAME))
				{
					String tryAgain;
					
					buffer.setLead(MILLISECONDS_IN_MEDIAPLAYER_BUFFER, true);					
					int waittime = buffer.getTimeToWaitForLead() / 1000;
						
					if (waittime <= 1)
					{
						tryAgain = Messages.getString("HttpPlayerServer.TRY_AGAIN_IN_1_SECOND"); //$NON-NLS-1$
					}
					else
					{
						tryAgain = Messages.getString("HttpPlayerServer.TRY_AGAIN_IN_SECONDS", new Integer(waittime));	 //$NON-NLS-1$
					}
					
					if (!icyMetadataFound)
					{
						// Normaler HTTP-Strom
						// Kein Shoutcast-Strom erlaubt
						// ----------------------------
						
						if (waittime > 0)
						{	
							writer.writeln("HTTP/1.0 503 " + tryAgain); //$NON-NLS-1$
							writer.writeln("Content-type: text/plain"); //$NON-NLS-1$
							writer.writeln();
							
							writer.setNewLineMark(NewLineWriter.LF);
							writer.writeln(tryAgain);
							if (shutdown)
								return;
							writer.flush();
							return;
						}
						else
						{
							writer.writeln("HTTP/1.0 200 OK"); //$NON-NLS-1$
							
							if (buffer.getMetadata().isICYStream())
							{
								// Eine ICY-Antwort geben, aber ohne Metadaten-Intervall
								writeAnswer(writer, "icy-", false); //$NON-NLS-1$
							}
							else
							{
								// Es wird wohl ein Icecast-Strom sein
								writeAnswer(writer, "ice-", false); //$NON-NLS-1$
							}
						}
					}
					else
					{
						// Shoutcast-Strom erlaubt
						// -----------------------
						
						if (waittime > 0)
						{	
							// Antwort nach HTTP oder Shoutcast-Art, je nach Stromdatentyp
							
							if (buffer.getMetadata().getServerProtocol().toUpperCase().equals("ICY")) //$NON-NLS-1$
							{
								writer.writeln("ICY 401 " + tryAgain); //$NON-NLS-1$

⌨️ 快捷键说明

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