package sound;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* A simple sound system.
*
* @author Dr. Kegel
*/
public final class SoundPlayer implements Closeable {
/**
* Provides strategies how to react, if being requested to play a sound file, which is already running.
*
* @author Dr. Kegel
*/
public enum PlayMode {
/**
* Restarts the sound from the beginning.
*/
Restart,
/**
* Ignores the second play request.
*/
Ignore,
/**
* Stops the first sound.
*/
Toggle,
/**
* Plays both sounds.
*/
Force,
}
//TODO: Debug counter
/**
* SoundEntries constructed
*/
public static AtomicInteger sector = new AtomicInteger();
/**
* SoundEntries played
*/
public static AtomicInteger sepl = new AtomicInteger();
/**
* SoundEntries closed (should be sector - number of sound files)
*/
public static AtomicInteger secl = new AtomicInteger();
/* immutable except counter */
private static ConcurrentHashMap<File, SoundEntry> clips;
public SoundPlayer() {
clips = new ConcurrentHashMap<>();
}
@Override
public void close() {
clips.values().forEach(sound.SoundEntry::close);
clips.clear();
}
/**
* Returns a {@code SoundEntry} instance based on the source file and {@link PlayMode} or creates a new one.
*
* @param file The source file.
* @return a {@code SoundEntry} instance.
* @throws IOException
*/
private SoundEntry getClip(File file) throws IOException {
SoundEntry result = new SoundEntry(file, clips.get(file), clips);
clips.put(file, result);
return result;
}
/**
* Returns a {@link Collection} with all playing files.
*
* @return a {@link Collection} with all playing files.
*/
public Collection<SoundEntry> getPlayingSounds() {
return clips.values().stream().filter(entry -> entry.getClip().isRunning()).collect(Collectors.toList());
}
/**
* Plays a sound file.
*
* @param file The sound file.
* @param mode The strategy for handling the case that the sound is already playing.
* @throws IOException
*/
public void play(File file, PlayMode mode) throws IOException {
if (file != null) getClip(file).play(mode);
}
/**
* @param file The sound file.
*/
public void stop(File file) {
SoundEntry entry = clips.get(file);
if (entry != null) {
entry.stop();
}
}
}