com.cloudgarden.audio
Class AudioSplitter
java.lang.Object
|
+--com.cloudgarden.audio.DefaultAudioObject
|
+--com.cloudgarden.audio.DefaultAudioSink
|
+--com.cloudgarden.audio.AudioSplitter
- All Implemented Interfaces:
- AudioObject, AudioSink, AudioSource
- public class AudioSplitter
- extends DefaultAudioSink
- implements AudioSource
A class designed to allow a single AudioSource to supply the same audio
data to multiple AudioSinks (useful, say, to broadcast speech to multiple
remote clients). AudioPipes should be used to connect the sinks to other
sinks (eg. AudioLineSinks) since they provide buffering and better speech
quality.
Here is an example which splits synthesized speech to three AudioLineSinks
and starts them at staggered intervals, so you can hear the three identical
but separate streams.
public static void main(String args[]) {
try {
synth = Central.createSynthesizer(new SynthesizerModeDesc(Locale.ENGLISH));
CGAudioManager audioMan = (CGAudioManager)synth.getAudioManager();
synth.allocate();
synth.resume();
SynthesizerProperties props = synth.getSynthesizerProperties();
Voice v1 = new Voice("Microsoft Mary",Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, "");
props.setVoice(v1);
synth.speakPlainText("ready",null);
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
SourceDataLine[] lines = new SourceDataLine[3];
AudioPipe[] pipes = new AudioPipe[3];
AudioFormat fmt;
if(audioMan.canSetAudioFormat()) {
fmt = new AudioFormat(22000,16,1,true,false);
audioMan.setAudioFormat(fmt);
}
fmt = audioMan.getAudioFormat();
System.out.println("Line format = "+fmt);
int bps = (int)(2*fmt.getSampleRate());
AudioSplitter splitter = new AudioSplitter();
audioMan.setSink(splitter);
splitter.startGetting();
for(int i=0;i<3;i++) {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt);
if (!AudioSystem.isLineSupported(info)) {
System.out.println("line not supported "+info);
return;
}
lines[i] = (SourceDataLine) AudioSystem.getLine(info);
pipes[i] = new AudioPipe();
//buffer must be big enough to hold 2*1.0 secs worth of data
//(the time between the first line starting and the third line starting)
//at 22000*2 bytes/sec
pipes[i].setBufferSize(2*bps);
pipes[i].setPauseInput(true);
pipes[i].setSink(new AudioLineSink(lines[i]));
splitter.addSink(pipes[i]);
}
Thread rt = new Thread() {
public void run() {
synth.speakPlainText("Hello world",null);
synth.speakPlainText("How are you this fine day?",null);
}
};
rt.start();
for(int i=0;i<3;i++) {
lines[i].open();
lines[i].start();
pipes[i].startGetting();
Thread.currentThread().sleep(1000);
}
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
audioMan.closeOutput();
//need to wait because output to stream occurs much faster than the
//SourceDataLine plays it
pipes[2].drain(); //wait for last line to finish
//...and now speak to the default audio device
audioMan.setSink(null);
synth.speakPlainText("and now I'm all done",null);
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
synth.deallocate();
//wait till we are deallocated...
synth.waitEngineState(Engine.DEALLOCATED);
} catch(Exception e2) {
e2.printStackTrace();
}
}
//...before closing up shop
System.exit(0);
}
Constructor Summary |
AudioSplitter()
Creates new SynthesizerAudioStream |
Method Summary |
void |
addSink(AudioSink sink)
Starts a thread which gets data from the source and writes (copies) it to all the sinks
added using the addSink method. |
void |
drain()
Blocks until END_OF_DATA is written to or read from this AudioObject. |
AudioSink |
getSink()
This method does nothing - use getSinks instead |
int |
getSinkCount()
|
java.util.Vector |
getSinks()
Returns a Vector of all AudioSinks added using the addSInk method |
boolean |
isSending()
Returns true if the thread started by the startSending method is
still writing data to the AudioSink. |
int |
read(byte[] data,
int len)
Cannot call this method - use the startSending method instead. |
int |
read(byte[] data,
int offset,
int len)
Cannot call this method - use the startSending method instead. |
boolean |
removeSink(AudioSink sink)
|
void |
setBufferSize(int size)
|
void |
setSink(AudioSink sink)
This method does nothing - use the addSink method instead |
void |
startSending()
This method should start a thread which repeatedly writes data to
the AudioSink object which this object is connected to, until it
writes data with length END_OF_DATA, or until the stopSending
method is called. |
void |
stopSending()
|
int |
write(byte[] data,
int offset,
int len)
Writes to all the sinks added using the addSInk method |
Methods inherited from class com.cloudgarden.audio.DefaultAudioObject |
addTransferListener, blockWhilePaused, blockWhileWaiting, bytesTransferred, canSetAudioFormat, getAudioFormat, getContentType, getLastException, isPaused, isWaiting, removeTransferListener, setPaused |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
AudioSplitter
public AudioSplitter()
- Creates new SynthesizerAudioStream
addSink
public void addSink(AudioSink sink)
throws java.io.IOException
- Starts a thread which gets data from the source and writes (copies) it to all the sinks
added using the addSink method.
getSinkCount
public int getSinkCount()
removeSink
public boolean removeSink(AudioSink sink)
write
public int write(byte[] data,
int offset,
int len)
throws java.io.IOException
- Writes to all the sinks added using the addSInk method
- See Also:
addSink(com.cloudgarden.audio.AudioSink)
startSending
public void startSending()
throws java.io.IOException
- Description copied from interface:
AudioSource
- This method should start a thread which repeatedly writes data to
the AudioSink object which this object is connected to, until it
writes data with length END_OF_DATA, or until the stopSending
method is called.
If an error occurs while the thread is sending data it
could be detected by calling the drain method.
- Specified by:
startSending
in interface AudioSource
- Following copied from interface:
com.cloudgarden.audio.AudioSource
- Throws:
an
- IOException if the source is unable to start sending data - for example,
if an audio file is unable to be opened to supply the data to be sent.- See Also:
AudioSource.setSink(com.cloudgarden.audio.AudioSink)
,
AudioObject.drain()
drain
public void drain()
throws java.io.IOException
- Description copied from interface:
AudioObject
- Blocks until END_OF_DATA is written to or read from this AudioObject.
For sinks such as an AudioLineSink, or sources such as AudioLineSource
should also drain the line.
- Specified by:
drain
in interface AudioObject
- Overrides:
drain
in class DefaultAudioObject
read
public int read(byte[] data,
int offset,
int len)
throws java.io.IOException
- Cannot call this method - use the startSending method instead.
- Specified by:
read
in interface AudioSource
- Following copied from interface:
com.cloudgarden.audio.AudioSource
- See Also:
AudioSource.setSink(com.cloudgarden.audio.AudioSink)
,
AudioSink#startGetting
,
AudioObject.setPaused(boolean)
read
public int read(byte[] data,
int len)
throws java.io.IOException
- Cannot call this method - use the startSending method instead.
- Specified by:
read
in interface AudioSource
isSending
public boolean isSending()
- Description copied from interface:
AudioSource
- Returns true if the thread started by the startSending method is
still writing data to the AudioSink.
- Specified by:
isSending
in interface AudioSource
- Following copied from interface:
com.cloudgarden.audio.AudioSource
- See Also:
AudioSource.startSending()
stopSending
public void stopSending()
- Specified by:
stopSending
in interface AudioSource
- Following copied from interface:
com.cloudgarden.audio.AudioSource
- See Also:
AudioSource.startSending()
setSink
public void setSink(AudioSink sink)
- This method does nothing - use the addSink method instead
- Specified by:
setSink
in interface AudioSource
- See Also:
addSink(com.cloudgarden.audio.AudioSink)
getSink
public AudioSink getSink()
- This method does nothing - use getSinks instead
- Specified by:
getSink
in interface AudioSource
- See Also:
addSink(com.cloudgarden.audio.AudioSink)
getSinks
public java.util.Vector getSinks()
- Returns a Vector of all AudioSinks added using the addSInk method
setBufferSize
public void setBufferSize(int size)