package paulscode.sound;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
/**
* The StreamThread class is used to process all streaming sources. This
* thread starts out asleep, and it sleeps when all streaming sources are
* finished playing, so it is necessary to call interrupt() after adding new
* streaming sources to the list.
*<br><br>
*<b><i> SoundSystem License:</b></i><br><b><br>
* You are free to use this library for any purpose, commercial or otherwise.
* You may modify this library or source code, and distribute it any way you
* like, provided the following conditions are met:
*<br>
* 1) You may not falsely claim to be the author of this library or any
* unmodified portion of it.
*<br>
* 2) You may not copyright this library or a modified version of it and then
* sue me for copyright infringement.
*<br>
* 3) If you modify the source code, you must clearly document the changes
* made before redistributing the modified source code, so other users know
* it is not the original code.
*<br>
* 4) You are not required to give me credit for this library in any derived
* work, but if you do, you must also mention my website:
* http://www.paulscode.com
*<br>
* 5) I the author will not be responsible for any damages (physical,
* financial, or otherwise) caused by the use if this library or any part
* of it.
*<br>
* 6) I the author do not guarantee, warrant, or make any representations,
* either expressed or implied, regarding the use of this library or any
* part of it.
* <br><br>
* Author: Paul Lamb
* <br>
* http://www.paulscode.com
* </b>
*
*/
public class StreamThread extends SimpleThread
{
/**
* Processes status messages, warnings, and error messages.
*/
private SoundSystemLogger logger;
/**
* List of sources that are currently streaming.
*/
private List<Source> streamingSources;
/**
* Used to synchronize access to the streaming sources list.
*/
private final Object listLock = new Object();
/**
* Constructor: Grabs a handle to the message logger and instantiates the
* streaming sources list.
*/
public StreamThread()
{
// grab a handle to the message logger:
logger = SoundSystemConfig.getLogger();
streamingSources = new LinkedList<Source>();
}
/**
* Removes all references to instantiated objects, and changes the thread's
* state to "not alive". Method alive() returns false when the cleanup()
* method has completed.
*/
@Override
protected void cleanup()
{
kill();
super.cleanup(); // Important!!
}
/**
* The main loop for processing commands. The thread sleeps when it finishes
* processing commands, and it must be interrupted to process more.
*/
@Override
public void run()
{
ListIterator<Source> iter;
Source src;
// Start out asleep:
snooze( 3600000 );
while( !dying() )
{
while( !dying() && !streamingSources.isEmpty() )
{
// Make sure noone else is accessing the list of sources:
synchronized( listLock )
{
iter = streamingSources.listIterator();
while( !dying() && iter.hasNext() )
{
src = iter.next();
if( src == null )
{
iter.remove();
}
else if( src.stopped() )
{
if( !src.rawDataStream )
iter.remove();
}
else if( !src.active() )
{
if( src.toLoop || src.rawDataStream )
src.toPlay = true;
iter.remove();
}
else if( !src.paused() )
{
src.checkFadeOut();
if( (!src.stream()) && (!src.rawDataStream) )
{
if( src.channel == null
|| !src.channel.processBuffer() )
{
// check if this is a looping source
if( src.toLoop )
{
// wait for stream to finish playing
if( !src.playing() )
{
// Generate an EOS event:
SoundSystemConfig.notifyEOS(
src.sourcename,
src.getSoundSequenceQueueSize()
);
// Check if the source is currently
// in the process of fading out.
if( src.checkFadeOut() )
{
// Source is fading out.
// Keep looping until it
// finishes.
src.preLoad = true;
}
else
{
// Source is not fading out.
// If there is another sound in
// the sequence, switch to it
// before replaying.
src.incrementSoundSequence();
src.preLoad = true; // replay
}
}
}
else
{
// wait for stream to finish playing
if( !src.playing() )
{
// Generate an EOS event:
SoundSystemConfig.notifyEOS(
src.sourcename,
src.getSoundSequenceQueueSize()
);
// Check if the source is currently
// in the process of fading out
if( !src.checkFadeOut() )
{
// Source is not fading out.
// Play anything else that is
// in the sound sequence queue.
if(
src.incrementSoundSequence() )
src.preLoad = true;
else
iter.remove(); // finished
}
}
}
}
}
}
}
}
if( !dying() && !streamingSources.isEmpty() )
snooze( 20 ); // sleep a bit so we don't peg the cpu
}
if( !dying() && streamingSources.isEmpty() )
snooze( 3600000 ); // sleep until there is more to do.
}
cleanup(); // Important!!
}
/**
* Adds a new streaming source to the list. If another source in the list is
* already playing on the same channel, it is stopped and removed from the
* list.
* @param source New source to stream.
*/
public void watch( Source source )
{
// make sure the source exists:
if( source == null )
return;
// make sure we aren't already watching this source:
if( streamingSources.contains( source ) )
return;
ListIterator<Source> iter;
Source src;
// Make sure noone else is accessing the list of sources:
synchronized( listLock )
{
// Any currently watched source which is null or playing on the
// same channel as the new source should be stopped and removed
// from the list.
iter = streamingSources.listIterator();
while( iter.hasNext() )
{
src = iter.next();
if( src == null )
{
iter.remove();
}
else if( source.channel == src.channel )
{
src.stop();
iter.remove();
}
}
// Add the new source to the list:
streamingSources.add( source );
}
}
/**
* Prints a message.
* @param message Message to print.
*/
private void message( String message )
{
logger.message( message, 0 );
}
/**
* Prints an important message.
* @param message Message to print.
*/
private void importantMessage( String message )
{
logger.importantMessage( message, 0 );
}
/**
* Prints the specified message if error is true.
* @param error True or False.
* @param message Message to print if error is true.
* @return True if error is true.
*/
private boolean errorCheck( boolean error, String message )
{
return logger.errorCheck( error, "StreamThread", message, 0 );
}
/**
* Prints an error message.
* @param message Message to print.
*/
private void errorMessage( String message )
{
logger.errorMessage( "StreamThread", message, 0 );
}
}