# JLayer player spielt nur eine mp3 Datei ab



## Rodi (13. Jul 2010)

Hallo zusammen!

Ich schreibe derzeit einen kleinen MP3-Player und verwende dazu JLayer von javazoom.net.

Das Abspielen einer MP3 funktioniert perfekt, wenn ich allerdings nach einer MP3 eine weitere aufrufe, wird dieser "Aufruf" ignoriert und somit nichts abgespielt.

Erwähnenswert ist evtl. noch, dass die MP3s aus dem Internet "gestreamt" werden, siehe AsynchronousBufferedInputStreamWrapper.java.

So, hier mal mein Code:

Klasse MP3Player.java

```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Christoph
 */

import java.net.URL;
import javazoom.jl.player.*;


public class MP3Player
{
    boolean debug = true;
    MP3Thread thread = null;
    Player player;
    AsynchronousBufferedInputStreamWrapper w;

    public MP3Player ()
    {
        if (debug)
            System.out.println ("MP3Player: Konstruktor");
    }

    public void play (String url)
    {
        if (thread != null)
        {
            stop ();
        }
        
        if (thread == null)
        {
            try
            {
                w= new AsynchronousBufferedInputStreamWrapper(new URL(url).openStream(), 10 * 96 * 1024);
                player = new Player (w);

                thread = new MP3Thread(player);
                thread.start();
            }
            catch (Exception e)
            {
                System.out.println ("ERROR: MP3Player: play ="+e);
            }
        }
    }

    public void pause ()
    {
        
    }

    public void stop ()
    {
        try
        {
            w.close();
            player.close ();
        }
        catch (Exception e)
        {
            System.out.println ("ERROR: MP3Player: stop ="+e);
        }
    }

    public int getPosition ()
    {
        return 0;
    }
}

/*******************************************************/
/***********************MP3THREAD***********************/
/*******************************************************/

class MP3Thread extends Thread
{
    private volatile Player player;
    
    MP3Thread (Player player)
    {
        this.player = player;
    }

    @Override
    public void run ()
    {
        try
        {
            player.play();
        }
        catch (Exception e)
        {
            System.out.println ("ERROR: MP3Thread run = "+e);
        }
    }
}
```

Klasse AsynchronousBufferedInputStreamWrapper.java


```
/*
 * Copyright (c)  2008  Johannes Schüth.
 * This file is part of SNPlayer
 *
 * SNPlayer 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 3 of the License, or
 * (at your option) any later version.
 *
 * SNPlayer 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 SNPlayer.  If not, see <http://www.gnu.org/licenses/>.
 */


import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

public class AsynchronousBufferedInputStreamWrapper extends InputStream {

	Thread thread;
	BufferingThread buffering;

	public AsynchronousBufferedInputStreamWrapper(InputStream inputStream,
			int bufferSizeInBytes) {

		buffering = new BufferingThread(this, new BufferedInputStream(
				inputStream, bufferSizeInBytes), bufferSizeInBytes);
	}

	public float getBufferLevel() {
		return buffering.getBufferLevel();
	}

	public void startBuffering() {
		System.out.println("Buffering started");
		thread = new Thread(buffering);
		thread.start();
	}

	@Override
	public synchronized void reset() throws IOException {
		System.out.println("Reset Called");
	}

	@Override
	public int read() throws IOException {

		if (this.thread == null) {
			System.out.println("MANUAL OVERRIDE!");
			startBuffering();
		}
		waitForCurrentByteBuffer();
		if (reachedEndOfStream()) {
			return -1;
		}

		byte b = buffering.currentByteBuffer[buffering.currentBufferPosition];
		buffering.currentBufferPosition++;
		buffering.overallBytesConsumed++;
		return b & 0xFF;
	}

	private boolean reachedEndOfStream() {
		return buffering.overallBytesConsumed == buffering.overallBytesBuffered;
	}

	private void waitForCurrentByteBuffer() {
		if (buffering.currentByteBuffer == null
				|| buffering.currentBufferPosition > buffering.currentByteBuffer.length - 1) {
			buffering.currentByteBuffer = null;
			while (buffering.currentByteBuffer == null && !reachedEndOfStream()) {
				// System.out.println("Getting Queue element");
				buffering.currentByteBuffer = buffering.dataQueue.poll();
				buffering.currentBufferPosition = 0;
				try {
					TimeUnit.MILLISECONDS.sleep(5L);
				} catch (InterruptedException e) {
					System.out.println(e);
				}
			}
		}
	}

	@Override
	public void close() throws IOException {
		super.close();
		this.thread.stop();
	}
}

class BufferingThread implements Runnable {

	AsynchronousBufferedInputStreamWrapper reference;

	public static final int DEFAULT_BUFFER_SEGMENTSIZE = 128 * 1024;
	volatile boolean eof = false;

	volatile BufferedInputStream wrappedInputStream;
	volatile ConcurrentLinkedQueue<byte[]> dataQueue;
	int maxDataQueueSize;
	volatile int overallBytesConsumed = 0;
	int currentBufferPosition;

	volatile int totalBufferSizeInBytes;
	volatile int bufferSizeInBytes;
	volatile int overallBytesBuffered;
	int lastCurrentBytesBuffered;
	int currentBytesBuffered;
	byte[] currentByteBuffer;

	public BufferingThread(AsynchronousBufferedInputStreamWrapper reference,
			BufferedInputStream wrappedInputStream, int totalBufferSizeInBytes) {

		this.reference = reference;
		this.wrappedInputStream = wrappedInputStream;
		this.dataQueue = new ConcurrentLinkedQueue<byte[]>();

		this.totalBufferSizeInBytes = totalBufferSizeInBytes;
		this.maxDataQueueSize = totalBufferSizeInBytes
				/ DEFAULT_BUFFER_SEGMENTSIZE;
		this.bufferSizeInBytes = DEFAULT_BUFFER_SEGMENTSIZE;

		System.out.println("totalBufferSizeInBytes: " + totalBufferSizeInBytes);
		System.out.println("maxDataQueueSize: " + maxDataQueueSize);
		System.out.println("bufferSizeInBytes: " + bufferSizeInBytes);

	}

	public float getBufferLevel() {
		System.out.println("overallBytesBuffered: " + overallBytesBuffered);
		System.out.println("overallBytesConsumed: " + overallBytesConsumed);
		System.out.println("dataQueue.size(): " + dataQueue.size());
		System.out.println("totalBufferSizeInBytes: " + totalBufferSizeInBytes);
		if (overallBytesBuffered == 0
				|| (overallBytesBuffered == overallBytesConsumed)) {
			return 0;
		}

		return (((float) overallBytesConsumed / (float) overallBytesBuffered) - 1)
				* -1;

	}

	public void run() {

		currentBytesBuffered = overallBytesBuffered - overallBytesConsumed;

		while (!eof) {

			try {

				// check if buffer is not full
				if (dataQueue.size() < maxDataQueueSize) {

					// System.out.println("Buffering...");
					ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

					// check if buffer is not full
					while (currentBytesBuffered < bufferSizeInBytes) {
						byte[] buffer = new byte[bufferSizeInBytes];
						int bytesRead = wrappedInputStream.read(buffer);

						if (bytesRead == -1) {
							// EOF
							System.out.println("EOF");
							wrappedInputStream.close();
							eof = true;
							break;
						}

						// writing bytes to os
						byteArrayOutputStream.write(buffer, 0, bytesRead);
						overallBytesBuffered += bytesRead;

						currentBytesBuffered = overallBytesBuffered
								- overallBytesConsumed;

					}

					if (!eof) {
						// Adding byte array to queue
						dataQueue.add(byteArrayOutputStream.toByteArray());
						currentBytesBuffered = 0;
					}

				} else {
					TimeUnit.MILLISECONDS.sleep(4L);
				}
			} catch (Exception e) {
				System.out.println(e);
			}
		}

		System.out.println("Finished Buffering");
	}
}
```

Aufrufsyntax:


```
MP3Player mp3player = new MP3Player ();
		//gui = new Gui (wg, db, mp3player);
                try
                {
                    mp3player.play("http://main.dance-tunes.com/idt/pk_site_api.request?p_message=%3Ctun_id%3E607900%3C%2Ftun_id%3E%3Ccmd%3Eget_preview%3C%2Fcmd%3E%3Csessie%3E1DZ0X1AXF7CDJR5667511854USB6QF%3C%2Fsessie%3E%3Csit_id%3E2%3C%2Fsit_id%3E%3Cuse_id%3E%3C%2Fuse_id%3E%3Cord_id%3E%3C%2Ford_id%3E%3Ctaal%3EENG%3C%2Ftaal%3E");

                    Thread.sleep (2000);
                    mp3player.stop ();
                    mp3player = null;
                    mp3player = new MP3Player ();
                    Thread.sleep (5000);
                    mp3player.play ("http://main.dance-tunes.com/idt/pk_site_api.request?p_message=%3Ctun_id%3E646370%3C%2Ftun_id%3E%3Ccmd%3Eget_preview%3C%2Fcmd%3E%3Csessie%3EVNLQ7E4UOON7HY56702280215FZY9Z%3C%2Fsessie%3E%3Csit_id%3E2%3C%2Fsit_id%3E%3Cuse_id%3E%3C%2Fuse_id%3E%3Cord_id%3E%3C%2Ford_id%3E%3Ctaal%3EENG%3C%2Ftaal%3E");
                }
                catch (Exception e)
                {
                    System.out.println (e);
                }
```

(Musikbeispiele stammen von dance-tunes.com und können dort kostenfrei angehört werden)

So. Nun zur Frage:

Weiß jemand woran es liegt, dass immer nur eine MP3 Datei abgespielt werden kann?

Ich bin natürlich selbst schon stundenlang auf Fehlersuche gegangen, allerdings ohne Erfolg.

Allerdings war eines auffällig: 
Ich habe mir die Klasse Player oder AdvancedPlayer mal angeschaut.

Klasse AdvancedPlayer.java:


```
/*
 * 11/19/04		1.0 moved to LGPL. 
 *-----------------------------------------------------------------------
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library 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 Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------
 */

package javazoom.jl.player.advanced;

import java.io.InputStream;

import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.BitstreamException;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.Header;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.decoder.SampleBuffer;
import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.FactoryRegistry;

/**
 * a hybrid of javazoom.jl.player.Player tweeked to include <code>play(startFrame, endFrame)</code>
 * hopefully this will be included in the api
 */
public class AdvancedPlayer
{
	/** The MPEG audio bitstream.*/
	private Bitstream bitstream;
	/** The MPEG audio decoder. */
	private Decoder decoder;
	/** The AudioDevice the audio samples are written to. */
	private AudioDevice audio;
	/** Has the player been closed? */
	private boolean closed = false;
	/** Has the player played back all frames from the stream? */
	private boolean complete = false;
        private boolean playing = true;
	private int lastPosition = 0;
	/** Listener for the playback process */
	private PlaybackListener listener;


	/**
	 * Creates a new <code>Player</code> instance.
	 */
	public AdvancedPlayer(InputStream stream) throws JavaLayerException
	{
		this(stream, null);
	}

	public AdvancedPlayer(InputStream stream, AudioDevice device) throws JavaLayerException
	{
		bitstream = new Bitstream(stream);

		if (device!=null) audio = device;
		else audio = FactoryRegistry.systemRegistry().createAudioDevice();
		audio.open(decoder = new Decoder());
	}

	public void play() throws JavaLayerException
	{
		play(Integer.MAX_VALUE);
	}

        public void pause () throws JavaLayerException
        {
            playing = !playing;
        }

	/**
	 * Plays a number of MPEG audio frames.
	 *
	 * @param frames	The number of frames to play.
	 * @return	true if the last frame was played, or false if there are
	 *			more frames.
	 */
	public boolean play(int frames) throws JavaLayerException
	{
		boolean ret = true;

		// report to listener
		if(listener != null) listener.playbackStarted(createEvent(PlaybackEvent.STARTED));

		while (frames-- > 0 && ret)
		{
                    if (playing)
                    {
			ret = decodeFrame();
                    }
                    else
                    {
                        try
                        {
                            Thread.sleep (10);
                        }
                        catch (Exception e)
                        {
                            
                        }
                    }
		}

//		if (!ret)
		{
			// last frame, ensure all data flushed to the audio device.
			AudioDevice out = audio;
			if (out != null)
			{
//				System.out.println(audio.getPosition());
				out.flush();
//				System.out.println(audio.getPosition());
				synchronized (this)
				{
					complete = (!closed);
					close();
				}

				// report to listener
				if(listener != null) listener.playbackFinished(createEvent(out, PlaybackEvent.STOPPED));
			}
		}
		return ret;
	}

	/**
	 * Cloases this player. Any audio currently playing is stopped
	 * immediately.
	 */
	public synchronized void close()
	{
		AudioDevice out = audio;
		if (out != null)
		{
			closed = true;
			audio = null;
			// this may fail, so ensure object state is set up before
			// calling this method.
			out.close();
			lastPosition = out.getPosition();
			try
			{
				bitstream.close();
			}
			catch (BitstreamException ex)
			{}
		}
	}

	/**
	 * Decodes a single frame.
	 *
	 * @return true if there are no more frames to decode, false otherwise.
	 */
	protected boolean decodeFrame() throws JavaLayerException
	{
		try
		{
			AudioDevice out = audio;
			if (out == null) return false;

			Header h = bitstream.readFrame();
			if (h == null) return false;

			// sample buffer set when decoder constructed
			SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);

			synchronized (this)
			{
				out = audio;
				if(out != null)
				{
					out.write(output.getBuffer(), 0, output.getBufferLength());
				}
			}

			bitstream.closeFrame();
		}
		catch (RuntimeException ex)
		{
			throw new JavaLayerException("Exception decoding audio frame", ex);
		}
		return true;
	}

	/**
	 * skips over a single frame
	 * @return false	if there are no more frames to decode, true otherwise.
	 */
	protected boolean skipFrame() throws JavaLayerException
	{
		Header h = bitstream.readFrame();
		if (h == null) return false;
		bitstream.closeFrame();
		return true;
	}

	/**
	 * Plays a range of MPEG audio frames
	 * @param start	The first frame to play
	 * @param end		The last frame to play
	 * @return true if the last frame was played, or false if there are more frames.
	 */
	public boolean play(final int start, final int end) throws JavaLayerException
	{
		boolean ret = true;
		int offset = start;
		while (offset-- > 0 && ret) ret = skipFrame();
		return play(end - start);
	}

	/**
	 * Constructs a <code>PlaybackEvent</code>
	 */
	private PlaybackEvent createEvent(int id)
	{
		return createEvent(audio, id);
	}

	/**
	 * Constructs a <code>PlaybackEvent</code>
	 */
	private PlaybackEvent createEvent(AudioDevice dev, int id)
	{
		return new PlaybackEvent(this, id, dev.getPosition());
	}

	/**
	 * sets the <code>PlaybackListener</code>
	 */
	public void setPlayBackListener(PlaybackListener listener)
	{
		this.listener = listener;
	}

	/**
	 * gets the <code>PlaybackListener</code>
	 */
	public PlaybackListener getPlayBackListener()
	{
		return listener;
	}

	/**
	 * closes the player and notifies <code>PlaybackListener</code>
	 */
	public void stop()
	{
		listener.playbackFinished(createEvent(PlaybackEvent.STOPPED));
		close();
	}
}
```

Beim 1. Aufruf einer MP3 meldet decodeFrame () immer "true" zurück, beim 2. immer false.

Das false tritt wegen 
	
	
	
	





```
if (out == null) return false;
```
 in der decodeFrame() Funktion auf.

Hoffentlich kann mir ein Java Experte helfen :bahnhof:

Gruß

Rodi

Edit: Alternativen für Javazoom sind natürlich auch gern gesehen.
Edit 2: Problem tritt nur bei Verwendung des AsynchronousBufferedInputStreamWrapper auf


----------



## Rodi (15. Jul 2010)

Lösung siehe hier:

Klick.


----------

