And here is the rest of the code:
StreamedSound.java
package sound;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class StreamedSound extends AbstractSound {
private SourceDataLine line;
private Player player;
private PlaybackStrategy playbackStrategy;
private boolean playing;
private boolean writing;
private int maxLineBufferSize;
public StreamedSound() {
playing = false;
writing = false;
maxLineBufferSize = 30000;
}
public void open() throws Exception {
player = Player.getInstance();
if (!isOpen()) {
load();
openLine();
// Initialize the playback strategy.
if (playbackStrategy == null) {
if (isCached()) {
playbackStrategy = new CachingStrategy();
} else {
playbackStrategy = new StreamingStrategy();
}
playbackStrategy.load();
}
player.start();
} else {
openLine();
}
}
void openLine() throws Exception {
DataLine.Info srcDataInfo = new DataLine.Info(SourceDataLine.class, getFormat());
line = (SourceDataLine) AudioSystem.getLine(srcDataInfo);
line.open(getFormat());
int frameSize = getFormat().getFrameSize();
// maxLineBufferSize = (line.getBufferSize() / frameSize / 2) * frameSize;
if (line == null) {
throw new Exception("SourceDataLine is null.");
}
line.start();
}
public void play() throws IOException {
stop();
while (writing) {
Thread.yield();
}
line.flush();
line.stop();
playbackStrategy.rewind();
playing = true;
line.start();
player.add(this);
}
/**
*
*/
public void stop() {
playing = false;
}
/**
* @return
*/
public boolean isPlaying() {
return playing;
}
public Object clone() throws CloneNotSupportedException {
StreamedSound sound = new StreamedSound();
copy(sound);
PlaybackStrategy strategy = (PlaybackStrategy) playbackStrategy.clone();
sound.setPlaybackStrategy(strategy);
return sound;
}
void setAudioData(byte[] data) {
if (isCached()) {
((CachingStrategy) playbackStrategy).setDataBuffer(data);
}
}
/**
* @throws IOException
*
*/
public void dispose() {
player.stop();
close();
}
protected void close() {
super.close();
line.close();
}
/**
* @return Returns the playbackStrategy.
*/
PlaybackStrategy getPlaybackStrategy() {
return playbackStrategy;
}
/**
* @param playbackStrategy The playbackStrategy to set.
*/
void setPlaybackStrategy(PlaybackStrategy playbackStrategy) {
this.playbackStrategy = playbackStrategy;
}
/**
* @author Jerome Blouin
*/
abstract class PlaybackStrategy {
abstract void load() throws IOException;
abstract void play() throws IOException;
abstract void rewind();
abstract public Object clone();
}
/**
* @author Jerome Blouin
*/
private class CachingStrategy extends PlaybackStrategy {
private byte[] buffer;
private int offset;
CachingStrategy() {
buffer = null;
offset = 0;
}
void load() throws IOException {
AudioInputStream stream = getAudioInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[maxLineBufferSize];
int bytesRead = 0;
while (bytesRead != -1) {
bytesRead = stream.read(data, 0, data.length);
if (bytesRead != -1) {
outStream.write(data, 0, bytesRead);
}
}
buffer = outStream.toByteArray();
outStream.close();
// System.out.println("" + buffer.length);
rewind();
}
void play() throws IOException {
writing = true;
if (offset < buffer.length) {
int lineBufferSize = maxLineBufferSize;
if (offset + lineBufferSize >= buffer.length) {
lineBufferSize = buffer.length - offset;
}
line.write(buffer, offset, lineBufferSize);
offset += lineBufferSize;
} else {
playing = false;
}
writing = false;
}
void rewind() {
offset = 0;
}
byte[] getDataBuffer() {
return buffer;
}
public Object clone() {
CachingStrategy strategy = new CachingStrategy();
strategy.setDataBuffer(buffer);
return strategy;
}
void setDataBuffer(byte[] data) {
buffer = data;
}
}
/**
* @author Jerome Blouin
*/
private class StreamingStrategy extends PlaybackStrategy {
private AudioInputStream stream;
private int bytesRead;
private byte[] buffer;
StreamingStrategy() {
stream = null;
buffer = new byte[maxLineBufferSize];
bytesRead = 0;
}
void load() throws IOException {
rewind();
}
void play() throws IOException {
writing = true;
bytesRead = stream.read(buffer, 0, buffer.length);
if (bytesRead != -1) {
line.write(buffer, 0, bytesRead);
} else {
playing = false;
}
writing = false;
}
void rewind() {
close();
try {
open();
} catch (Exception e) {
e.printStackTrace();
}
stream = getAudioInputStream();
bytesRead = 0;
}
public Object clone() {
return new StreamingStrategy();
}
}
}
Player
package sound;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
class Player {
private SoundThread thread;
private boolean running;
private static Player instance = null;
private Player() {
running = false;
}
static Player getInstance() {
if (instance == null) {
instance = new Player();
}
return instance;
}
void start() {
if (!running) {
thread = new SoundThread();
thread.start();
running = true;
}
}
void add(StreamedSound sound) {
thread.add(sound);
}
/**
* @param running The running to set.
*/
void stop() {
thread.stop();
running = false;
}
private class SoundThread implements Runnable {
private Thread thread;
private List sounds;
private int soundCount;
private boolean running;
SoundThread() {
sounds = new ArrayList();
soundCount = 0;
running = false;
}
void start() {
if (!running) {
thread = new Thread(this);
thread.start();
}
}
void add(StreamedSound sound) {
sounds.add(sound);
soundCount++;
}
void remove(StreamedSound sound) {
if (isRunning()) {
throw new IllegalStateException("Can not unregister sound while this thread running.");
}
sounds.remove(sound);
soundCount--;
}
/**
* @return Returns the soundCount.
*/
int getSoundCount() {
return soundCount;
}
public void run() {
running = true;
StreamedSound sound;
while (running) {
for (int i = 0; i < soundCount; i++) {
sound = (StreamedSound) sounds.get(i);
if (sound.isPlaying()) {
try {
sound.getPlaybackStrategy().play();
} catch (IOException e) {
throw new RuntimeException("Unable to play streamed sound.", e);
}
if (!sound.isPlaying()) {
sounds.remove(i);
soundCount--;
i--;
}
}
Thread.yield();
}
if (soundCount == 0) {
Thread.yield();
}
}
}
/**
* @return Returns the running.
*/
boolean isRunning() {
return running;
}
/**
* @param running The running to set.
*/
void stop() {
running = false;
while (thread.isAlive()) {
Thread.yield();
}
}
}
}