don't play sounds with clips, instead have threads that spool sound
data to open lines. Joy. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1986 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: SoundManager.java,v 1.25 2002/11/22 19:21:12 ray Exp $
|
// $Id: SoundManager.java,v 1.26 2002/11/23 02:09:36 ray Exp $
|
||||||
|
|
||||||
package com.threerings.media;
|
package com.threerings.media;
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@ import javax.sound.sampled.LineListener;
|
|||||||
import javax.sound.sampled.LineUnavailableException;
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
import javax.sound.sampled.Mixer;
|
import javax.sound.sampled.Mixer;
|
||||||
import javax.sound.sampled.Mixer;
|
import javax.sound.sampled.Mixer;
|
||||||
|
import javax.sound.sampled.SourceDataLine;
|
||||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||||
|
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
@@ -134,18 +135,11 @@ public class SoundManager
|
|||||||
} else if (UNLOCK == command) {
|
} else if (UNLOCK == command) {
|
||||||
_clipCache.unlock(key);
|
_clipCache.unlock(key);
|
||||||
|
|
||||||
} else if (FLUSH == command) {
|
|
||||||
flushResources(false);
|
|
||||||
// and re-start the resource freer timer
|
|
||||||
// to do it again in 3 seconds
|
|
||||||
_resourceFreer.restart();
|
|
||||||
|
|
||||||
} else if (UPDATE_MUSIC_VOL == command) {
|
} else if (UPDATE_MUSIC_VOL == command) {
|
||||||
updateMusicVolume();
|
updateMusicVolume();
|
||||||
|
|
||||||
} else if (DIE == command) {
|
} else if (DIE == command) {
|
||||||
_resourceFreer.stop();
|
// TODO: clean up more stuff.
|
||||||
flushResources(true);
|
|
||||||
shutdownMusic();
|
shutdownMusic();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -159,9 +153,6 @@ public class SoundManager
|
|||||||
|
|
||||||
_player.setDaemon(true);
|
_player.setDaemon(true);
|
||||||
_player.start();
|
_player.start();
|
||||||
|
|
||||||
_resourceFreer.setRepeats(false);
|
|
||||||
_resourceFreer.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,25 +320,17 @@ public class SoundManager
|
|||||||
*/
|
*/
|
||||||
protected void playSound (SoundKey key)
|
protected void playSound (SoundKey key)
|
||||||
{
|
{
|
||||||
// see if we can restart a previously used sound that's still
|
|
||||||
// hanging out.
|
|
||||||
if (restartSound(key)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// get the sound data from our LRU cache
|
// get the sound data from our LRU cache
|
||||||
ClipInfo info = getClipData(key);
|
byte[] data = getClipData(key);
|
||||||
if (info == null) {
|
if (data == null) {
|
||||||
return; // borked!
|
return; // borked!
|
||||||
}
|
}
|
||||||
|
|
||||||
Clip clip = (Clip) AudioSystem.getLine(info.info);
|
AudioInputStream stream = AudioSystem.getAudioInputStream(
|
||||||
clip.open(info.stream);
|
new ByteArrayInputStream(data));
|
||||||
|
|
||||||
SoundRecord rec = new SoundRecord(key, clip);
|
LineSpooler.play(stream, _clipVol);
|
||||||
rec.start(_clipVol);
|
|
||||||
_activeClips.add(rec);
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.warning("Error loading sound file [key=" + key +
|
Log.warning("Error loading sound file [key=" + key +
|
||||||
@@ -363,31 +346,11 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to reuse a clip that's already been loaded.
|
|
||||||
*/
|
|
||||||
protected boolean restartSound (SoundKey key)
|
|
||||||
{
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
// we just go through all the sounds. There'll be 32 max, so fuckit.
|
|
||||||
for (int ii=0, nn=_activeClips.size(); ii < nn; ii++) {
|
|
||||||
SoundRecord rec = (SoundRecord) _activeClips.get(ii);
|
|
||||||
if (rec.key.equals(key) && rec.isStoppedSince(now)) {
|
|
||||||
rec.restart(_clipVol);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a song from the specified path.
|
* Play a song from the specified path.
|
||||||
*/
|
*/
|
||||||
protected void playMusic (MusicInfo info)
|
protected void playMusic (MusicInfo info)
|
||||||
{
|
{
|
||||||
Log.info("Playing: " + info);
|
|
||||||
// stop whatever's currently playing
|
// stop whatever's currently playing
|
||||||
if (_musicPlayer != null) {
|
if (_musicPlayer != null) {
|
||||||
_musicPlayer.stop();
|
_musicPlayer.stop();
|
||||||
@@ -502,14 +465,11 @@ public class SoundManager
|
|||||||
*/
|
*/
|
||||||
protected void stopMusic (SoundKey key)
|
protected void stopMusic (SoundKey key)
|
||||||
{
|
{
|
||||||
Log.info("Stopping: " + key);
|
|
||||||
if (! _musicStack.isEmpty()) {
|
if (! _musicStack.isEmpty()) {
|
||||||
MusicInfo current = (MusicInfo) _musicStack.getFirst();
|
MusicInfo current = (MusicInfo) _musicStack.getFirst();
|
||||||
|
|
||||||
// if we're currently playing this song..
|
// if we're currently playing this song..
|
||||||
if (key.equals(current)) {
|
if (key.equals(current)) {
|
||||||
Log.info("is top song!");
|
|
||||||
|
|
||||||
// stop it
|
// stop it
|
||||||
_musicPlayer.stop();
|
_musicPlayer.stop();
|
||||||
|
|
||||||
@@ -517,6 +477,7 @@ public class SoundManager
|
|||||||
_musicStack.removeFirst();
|
_musicStack.removeFirst();
|
||||||
// start playing the next..
|
// start playing the next..
|
||||||
playTopMusic();
|
playTopMusic();
|
||||||
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// we aren't currently playing this song. Simply remove.
|
// we aren't currently playing this song. Simply remove.
|
||||||
@@ -559,49 +520,20 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called occaisionally to flush sound resources.
|
|
||||||
*
|
|
||||||
* @param force if true, shutdown and free all sounds, no matter what.
|
|
||||||
* If false, frees sounds that haven't been used since EXPIRE_TIME
|
|
||||||
* ago.
|
|
||||||
*/
|
|
||||||
protected void flushResources (boolean force)
|
|
||||||
{
|
|
||||||
long then = System.currentTimeMillis() - EXPIRE_TIME;
|
|
||||||
|
|
||||||
for (Iterator iter=_activeClips.iterator(); iter.hasNext(); ) {
|
|
||||||
SoundRecord rec = (SoundRecord) iter.next();
|
|
||||||
if (force || rec.isStoppedSince(then)) {
|
|
||||||
iter.remove();
|
|
||||||
rec.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the audio data for the specified path.
|
* Get the audio data for the specified path.
|
||||||
*/
|
*/
|
||||||
protected ClipInfo getClipData (SoundKey key)
|
protected byte[] getClipData (SoundKey key)
|
||||||
throws IOException, UnsupportedAudioFileException
|
throws IOException, UnsupportedAudioFileException
|
||||||
{
|
{
|
||||||
ClipInfo info = (ClipInfo) _clipCache.get(key);
|
byte[] data = (byte[]) _clipCache.get(key);
|
||||||
if (info != null) {
|
if (data == null) {
|
||||||
// we are re-using an old stream, make sure to rewind it.
|
data = StreamUtils.streamAsBytes(
|
||||||
info.stream.reset();
|
_rmgr.getResource(key.set, key.path), BUFFER_SIZE);
|
||||||
|
_clipCache.put(key, data);
|
||||||
} else {
|
|
||||||
// set it up and put it in the cache
|
|
||||||
AudioInputStream stream = AudioSystem.getAudioInputStream(
|
|
||||||
new ByteArrayInputStream(StreamUtils.streamAsBytes(
|
|
||||||
_rmgr.getResource(key.set, key.path), BUFFER_SIZE)));
|
|
||||||
DataLine.Info dinfo = new DataLine.Info(
|
|
||||||
Clip.class, stream.getFormat());
|
|
||||||
info = new ClipInfo(dinfo, stream);
|
|
||||||
_clipCache.put(key, info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
@@ -651,162 +583,187 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A record to help us manage the use of sound resources.
|
* Handles the playing of sound clip data.
|
||||||
* We don't free the resources associated with a clip immediately, because
|
|
||||||
* it may be played again shortly.
|
|
||||||
*/
|
*/
|
||||||
protected static class SoundRecord
|
protected static class LineSpooler extends Thread
|
||||||
implements LineListener
|
|
||||||
{
|
{
|
||||||
public SoundKey key;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a SoundRecord.
|
* Attempt to play the specified sound.
|
||||||
*/
|
*/
|
||||||
public SoundRecord (SoundKey key, Clip clip)
|
public static void play (AudioInputStream stream, float volume)
|
||||||
|
throws LineUnavailableException
|
||||||
{
|
{
|
||||||
this.key = key;
|
AudioFormat format = stream.getFormat();
|
||||||
_clip = clip;
|
LineSpooler spooler;
|
||||||
|
|
||||||
// The mess:
|
for (int ii=0, nn=_available.size(); ii < nn; ii++) {
|
||||||
// If we restart a sample, we get two stop events, one immediately
|
spooler = (LineSpooler) _available.get(ii);
|
||||||
// and one later on.
|
|
||||||
// We can't just ignore the first in that case, because once
|
|
||||||
// a sample is restarted it seems to not return true
|
|
||||||
// for isRunning() (maybe because it's already been reset?)
|
|
||||||
// but will continue to generate stop events each time it
|
|
||||||
// is started.
|
|
||||||
//
|
|
||||||
// So- we can't depend on capturing stop events to know
|
|
||||||
// when a sound is done playing. Instead we just add the length
|
|
||||||
// of the sound to the current time. We fall back on the
|
|
||||||
// LineListener method if the clip length is unavailable.
|
|
||||||
//
|
|
||||||
// The good news is that just adding the length is in many
|
|
||||||
// ways a better system. I don't feel confident in doing
|
|
||||||
// that right now because I don't know if any sounds
|
|
||||||
// will ever return NOT_SPECIFIED.
|
|
||||||
|
|
||||||
long length = _clip.getMicrosecondLength();
|
// we have this thread remove the spooler if it's dead
|
||||||
if (length == AudioSystem.NOT_SPECIFIED) {
|
// so that we avoid deadlock conditions
|
||||||
Log.info("Length of AudioClip not specified, falling back " +
|
if (spooler.isDead()) {
|
||||||
"to listening for stop events.");
|
_available.remove(ii--);
|
||||||
_clip.addLineListener(this);
|
nn--;
|
||||||
_length = AudioSystem.NOT_SPECIFIED;
|
|
||||||
|
|
||||||
} else {
|
} else if (spooler.checkPlay(format, stream, volume)) {
|
||||||
// convert microseconds to milliseconds, round up.
|
return;
|
||||||
_length = (length / 1000L) + 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (_available.size() >= MAX_SPOOLERS) {
|
||||||
* Start playing the sound.
|
throw new LineUnavailableException("Exceeded maximum number " +
|
||||||
*/
|
"of narya sound spoolers.");
|
||||||
public void start (float volume)
|
|
||||||
{
|
|
||||||
adjustVolume(_clip, volume);
|
|
||||||
_clip.start();
|
|
||||||
didStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restart the sound from the beginning.
|
|
||||||
*/
|
|
||||||
public void restart (float volume)
|
|
||||||
{
|
|
||||||
// this only gets called after the sound has stopped, so
|
|
||||||
// simply rewind and replay.
|
|
||||||
_clip.setFramePosition(0);
|
|
||||||
start(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop playing the sound.
|
|
||||||
*/
|
|
||||||
public void stop ()
|
|
||||||
{
|
|
||||||
_clip.stop();
|
|
||||||
didStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close down this SoundRecord and free the resources associated
|
|
||||||
* with the clip.
|
|
||||||
*/
|
|
||||||
public void close ()
|
|
||||||
{
|
|
||||||
if (areListening()) {
|
|
||||||
_clip.removeLineListener(this);
|
|
||||||
}
|
}
|
||||||
if (_clip.isRunning()) {
|
|
||||||
_clip.stop();
|
spooler = new LineSpooler(format);
|
||||||
|
_available.add(spooler);
|
||||||
|
spooler.checkPlay(format, stream, volume);
|
||||||
|
spooler.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor.
|
||||||
|
*/
|
||||||
|
private LineSpooler (AudioFormat format)
|
||||||
|
throws LineUnavailableException
|
||||||
|
{
|
||||||
|
super("narya SoundManager LineSpooler");
|
||||||
|
_format = format;
|
||||||
|
|
||||||
|
_line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(
|
||||||
|
SourceDataLine.class, _format));
|
||||||
|
_line.open(_format);
|
||||||
|
_line.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has this line been closed?
|
||||||
|
*/
|
||||||
|
protected boolean isDead ()
|
||||||
|
{
|
||||||
|
return !_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check-and-set method to see if we can play and to start
|
||||||
|
* doing so if we can.
|
||||||
|
*/
|
||||||
|
protected synchronized boolean checkPlay (
|
||||||
|
AudioFormat format, AudioInputStream stream, float volume)
|
||||||
|
{
|
||||||
|
if (_valid && (_stream == null) && _format.matches(format)) {
|
||||||
|
_stream = stream;
|
||||||
|
SoundManager.adjustVolume(_line, volume);
|
||||||
|
notify();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
_clip.close();
|
|
||||||
|
|
||||||
// make sure nobody uses this SoundRecord again
|
return false;
|
||||||
_clip = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that we've started playback of this sound.
|
* @return true if we have sound data to play.
|
||||||
*/
|
*/
|
||||||
protected void didStart ()
|
protected synchronized boolean waitForData ()
|
||||||
{
|
{
|
||||||
if (areListening()) {
|
if (_stream == null) {
|
||||||
// clear out the stamp so that we can't possibly be reaped
|
try {
|
||||||
// and since we're listening, we'll eventually call didStop()
|
wait(MAX_WAIT_TIME);
|
||||||
_stamp = Long.MAX_VALUE;
|
} catch (InterruptedException ie) {
|
||||||
|
// ignore.
|
||||||
} else {
|
}
|
||||||
_stamp = System.currentTimeMillis() + _length;
|
if (_stream == null) {
|
||||||
|
_valid = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that we've stopped playback.
|
* Main loop for the LineSpooler.
|
||||||
*/
|
*/
|
||||||
protected void didStop ()
|
public void run ()
|
||||||
{
|
{
|
||||||
// no matter what, when we stop, we stop
|
while (waitForData()) {
|
||||||
_stamp = System.currentTimeMillis();
|
playStream();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this SoundRecord been stopped since before the specified time?
|
|
||||||
*/
|
|
||||||
public boolean isStoppedSince (long then)
|
|
||||||
{
|
|
||||||
return (_stamp < then);
|
|
||||||
}
|
|
||||||
|
|
||||||
// documentation inherited from interface LineListener
|
|
||||||
public void update (LineEvent event)
|
|
||||||
{
|
|
||||||
// this only gets run if we actually need to listen for the
|
|
||||||
// stop events.
|
|
||||||
if (event.getType() == LineEvent.Type.STOP) {
|
|
||||||
didStop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_line.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we registered as a LineListener on our clip?
|
* Play the current stream.
|
||||||
*/
|
*/
|
||||||
private final boolean areListening ()
|
protected void playStream ()
|
||||||
{
|
{
|
||||||
return _length == AudioSystem.NOT_SPECIFIED;
|
int count = 0;
|
||||||
|
byte[] data = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
while (count != -1) {
|
||||||
|
try {
|
||||||
|
count = _stream.read(data, 0, data.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// this shouldn't ever ever happen
|
||||||
|
Log.warning("Error reading clip data! [e=" + e + "].");
|
||||||
|
_stream = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= 0) {
|
||||||
|
_line.write(data, 0, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_line.isActive()) {
|
||||||
|
// Log.info("Waiting for drain (" + hashCode() + ", active=" +
|
||||||
|
// _line.isActive() + ", running=" + _line.isRunning()+
|
||||||
|
// ") : " + incDrainers());
|
||||||
|
|
||||||
|
// wait for it to play all the way
|
||||||
|
_line.drain();
|
||||||
|
|
||||||
|
// Log.info("drained: (" + hashCode() + ") :" + decDrainers());
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear it out so that we can wait for more.
|
||||||
|
_stream = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The timestamp of the moment this clip last stopped playing. */
|
// protected static final synchronized int incDrainers ()
|
||||||
protected long _stamp;
|
// {
|
||||||
|
// return ++drainers;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected static final synchronized int decDrainers ()
|
||||||
|
// {
|
||||||
|
// return --drainers;
|
||||||
|
// }
|
||||||
|
// static int drainers = 0;
|
||||||
|
|
||||||
/** The length of the clip, in milliseconds, or
|
/** The format that our line was opened with. */
|
||||||
* AudioSystem.NOT_SPECIFIED if unknown. */
|
protected AudioFormat _format;
|
||||||
protected long _length;
|
|
||||||
|
|
||||||
/** The clip we're wrapping. */
|
/** The stream we're currently spooling out. */
|
||||||
protected Clip _clip;
|
protected AudioInputStream _stream;
|
||||||
|
|
||||||
|
/** The line that we spool to. */
|
||||||
|
protected SourceDataLine _line;
|
||||||
|
|
||||||
|
/** Are we still active and usable for spooling sounds, or should
|
||||||
|
* we be removed. */
|
||||||
|
protected boolean _valid = true;
|
||||||
|
|
||||||
|
/** The list of all the currently instantiated spoolers. */
|
||||||
|
protected static ArrayList _available = new ArrayList();
|
||||||
|
|
||||||
|
/** The maximum time a spooler will wait for a stream before
|
||||||
|
* deciding to shut down. */
|
||||||
|
protected static final long MAX_WAIT_TIME = 30000L;
|
||||||
|
|
||||||
|
/** The maximum number of spoolers we'll allow. This is a lot. */
|
||||||
|
protected static final int MAX_SPOOLERS = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -848,24 +805,6 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A wee helper class that holds clip information in our cache.
|
|
||||||
*/
|
|
||||||
protected static class ClipInfo
|
|
||||||
{
|
|
||||||
/** The information needed to construct a clip from the stream. */
|
|
||||||
public DataLine.Info info;
|
|
||||||
|
|
||||||
/** The data to be used to make the clip. */
|
|
||||||
public AudioInputStream stream;
|
|
||||||
|
|
||||||
public ClipInfo (DataLine.Info info, AudioInputStream stream)
|
|
||||||
{
|
|
||||||
this.info = info;
|
|
||||||
this.stream = stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that tracks the information about our playing music files.
|
* A class that tracks the information about our playing music files.
|
||||||
*/
|
*/
|
||||||
@@ -881,19 +820,6 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Every 3 seconds we look for sounds that haven't been used for 4 and
|
|
||||||
* free them up.
|
|
||||||
*/
|
|
||||||
protected Timer _resourceFreer = new Timer(3000,
|
|
||||||
new ActionListener() {
|
|
||||||
public void actionPerformed (ActionEvent e)
|
|
||||||
{
|
|
||||||
// request a sweep by the main thread
|
|
||||||
_queue.append(FLUSH);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/** The resource manager from which we obtain audio files. */
|
/** The resource manager from which we obtain audio files. */
|
||||||
protected ResourceManager _rmgr;
|
protected ResourceManager _rmgr;
|
||||||
|
|
||||||
@@ -928,16 +854,11 @@ public class SoundManager
|
|||||||
protected Object UPDATE_MUSIC_VOL = new Object();
|
protected Object UPDATE_MUSIC_VOL = new Object();
|
||||||
protected Object LOCK = new Object();
|
protected Object LOCK = new Object();
|
||||||
protected Object UNLOCK = new Object();
|
protected Object UNLOCK = new Object();
|
||||||
protected Object FLUSH = new Object();
|
|
||||||
protected Object DIE = new Object();
|
protected Object DIE = new Object();
|
||||||
|
|
||||||
/** The queue size at which we start to ignore requests to play sounds. */
|
/** The queue size at which we start to ignore requests to play sounds. */
|
||||||
protected static final int MAX_QUEUE_SIZE = 100;
|
protected static final int MAX_QUEUE_SIZE = 25;
|
||||||
|
|
||||||
/** The buffer size in bytes used when reading audio file data. */
|
/** The buffer size in bytes used when reading audio file data. */
|
||||||
protected static final int BUFFER_SIZE = 2048;
|
protected static final int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
/** How long a clip may linger after stopping before we clear
|
|
||||||
* its resources. */
|
|
||||||
protected static final long EXPIRE_TIME = 4000L;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user