📄 datasourcehandler.java
字号:
/*
* DataSourceHandler.java
*
* Created on March 20, 2003, 10:56 AM
*/
package gov.nist.applet.phone.media.messaging;
import java.util.Enumeration;
import java.util.Vector;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.media.DataSink;
import javax.media.MediaLocator;
import javax.media.Control;
import javax.media.datasink.DataSinkErrorEvent;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.protocol.SourceTransferHandler;
import javax.media.protocol.PushDataSource;
import javax.media.protocol.PushSourceStream;
import javax.media.protocol.PullDataSource;
import javax.media.protocol.DataSource;
import javax.media.protocol.SourceStream;
import javax.media.IncompatibleSourceException;
/**
* This Data source Handler allow one to write directly from a DataSource
* to an array of byte.
* This Data Source Handler allow one to fill a buffer with MPEG_AUDIO
* or GSM audio data.
* Example : One can record his voice from a microphone to a buffer in either a
* MP3 or GSM format. To get the buffer with the recorded voice just call the
* getRecordBuffer method
* @author Jean Deruelle <jean.deruelle@nist.gov>
*
* <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
*/
public class DataSourceHandler
implements DataSink, SourceTransferHandler, Runnable{
//DataSink listeners
protected Vector listeners = new Vector(1);
final private static boolean DEBUG = false;
//states
final protected static int NOT_INITIALIZED = 0;
final protected static int OPENED = 1;
final protected static int STARTED = 2;
final protected static int CLOSED = 3;
//current state
protected int state = NOT_INITIALIZED;
protected DataSource source;
protected SourceStream [] streams;
protected SourceStream stream;
protected boolean push;
protected Control [] controls;
//protected MediaLocator locator = null;
protected String contentType = null;
protected int bytesWritten = 0;
protected static final int BUFFER_LEN = 128 * 1024;
protected boolean syncEnabled = false;
long lastSyncTime = -1;
ByteArrayOutputStream baout=null;
protected byte [] buffer1 = new byte[BUFFER_LEN];
protected byte [] buffer2 = new byte[BUFFER_LEN];
protected boolean buffer1Pending = false;
protected long buffer1PendingLocation = -1;
protected int buffer1Length;
protected boolean buffer2Pending = false;
protected long buffer2PendingLocation = -1;
protected int buffer2Length;
protected long nextLocation = 0;
protected Thread writeThread = null;
private Integer bufferLock = new Integer(0);
private boolean receivedEOS = false;
public int WRITE_CHUNK_SIZE = 16384;
private boolean streamingEnabled = false;
/**
* Constructs a new DataSourceHandler
*/
public DataSourceHandler(){
baout=new ByteArrayOutputStream();
}
/**
* Set the data source of this data source handler
* @exception IncompatibleSourceException - if the data source cannot be
* handled, this exception is thrown
*/
public void setSource(DataSource ds) throws IncompatibleSourceException {
if (!(ds instanceof PushDataSource) &&
!(ds instanceof PullDataSource)) {
throw new IncompatibleSourceException("Incompatible datasource");
}
source = ds;
if (source instanceof PushDataSource) {
push = true;
try {
((PushDataSource) source).connect();
} catch (IOException ioe) {
}
streams = ((PushDataSource) source).getStreams();
} else {
push = false;
try {
((PullDataSource) source).connect();
} catch (IOException ioe) {
}
streams = ((PullDataSource) source).getStreams();
}
if (streams == null || streams.length != 1)
throw new IncompatibleSourceException("DataSource should have 1 stream");
stream = streams[0];
contentType = source.getContentType();
if (push)
((PushSourceStream)stream).setTransferHandler(this);
}
/**
* Set the output <code>MediaLocator</code>.
* This method should only be called once; an error is thrown if
* the locator has already been set.
* @param output <code>MediaLocator</code> that describes where
* the output goes.
*/
public void setOutputLocator(MediaLocator output) {
//locator = output;
}
/*public void setEnabled(boolean b) {
streamingEnabled = b;
}
public void setSyncEnabled() {
syncEnabled = true;
}*/
/**
* Our DataSink does not need to be opened.
*/
public void open() {
}
/**
* @see javax.media.DataSink#getOutputLocator()
*/
public MediaLocator getOutputLocator() {
return null;
//return locator;
}
/**
* @see javax.media.DataSink#start()
*/
public void start() throws IOException {
//System.out.println("DATASOURCEHANDLER: start : source: "+source);
if (source != null)
source.start();
if (writeThread == null) {
writeThread = new Thread(this);
writeThread.setName("DataSourceHandler Thread");
writeThread.start();
}
setState(STARTED);
}
/**
* Stop the data-transfer.
* If the source has not been connected and started,
* <CODE>stop</CODE> does nothing.
*/
public void stop() throws IOException {
//System.out.println("DATASOURCEHANDLER: stop");
if (state == STARTED) {
if (source != null)
source.stop();
setState(OPENED);
}
}
/**
* Set the state of this data source handler
*/
protected void setState(int state) {
synchronized(this) {
this.state = state;
}
}
/**
* @see javax.media.DataSink#close()
*/
public final void close() {
synchronized(this) {
if ( state == CLOSED )
return;
setState(CLOSED);
}
if (push) {
for (int i = 0; i < streams.length; i++) {
((PushSourceStream)streams[i]).setTransferHandler(null);
}
}
try {
source.stop();
} catch (IOException e) {
System.err.println("IOException when stopping source " + e);
}
// Disconnect the data source
if (source != null)
source.disconnect();
removeAllListeners();
//writeBufferToFile("d://temp//test.mp3");
}
/**
* Get the current content type for this data source handler
*
* @return The current <CODE>ContentDescriptor</CODE> for this data source handler.
*/
public String getContentType() {
return contentType;
}
/**
* Obtain the collection of objects that
* control the object that implements this interface.
* <p>
*
* No controls are supported.
* A zero length array is returned.
*
* @return A zero length array
*/
public Object [] getControls() {
if (controls == null) {
controls = new Control[0];
}
return controls;
}
/**
* Obtain the object that implements the specified
* <code>Class</code> or <code>Interface</code>
* The full class or interface name must be used.
* <p>
*
* The control is not supported.
* <code>null</code> is returned.
*
* @return <code>null</code>.
*/
public Object getControl(String controlName) {
return null;
}
/*
* @see javax.media.protocol.SourceTransferHandler#transferData(javax.media.protocol.PushSourceStream)
*/
public synchronized void transferData(PushSourceStream pss) {
if(state==STARTED){
int totalRead = 0;
int spaceAvailable = BUFFER_LEN;
int bytesRead = 0;
if (buffer1Pending) {
synchronized (bufferLock) {
while (buffer1Pending) {
if (DEBUG) System.err.println("Waiting for free buffer");
try {
bufferLock.wait();
} catch (InterruptedException ie) {
}
}
}
if (DEBUG) System.err.println("Got free buffer");
}
// System.err.println("In transferData()");
while (spaceAvailable > 0) {
try {
bytesRead = pss.read(buffer1, totalRead, spaceAvailable);
//System.err.println("bytesRead = " + bytesRead);
if (bytesRead > 16 * 1024 && WRITE_CHUNK_SIZE < 32 * 1024) {
if ( bytesRead > 64 * 1024 &&
WRITE_CHUNK_SIZE < 128 * 1024 )
WRITE_CHUNK_SIZE = 128 * 1024;
else if ( bytesRead > 32 * 1024 &&
WRITE_CHUNK_SIZE < 64 * 1024 )
WRITE_CHUNK_SIZE = 64 * 1024;
else if ( WRITE_CHUNK_SIZE < 32 * 1024 )
WRITE_CHUNK_SIZE = 32 * 1024;
//System.err.println("Increasing buffer to " + WRITE_CHUNK_SIZE);
}
} catch (IOException ioe) {
// What to do here?
}
if (bytesRead <= 0) {
break;
}
totalRead += bytesRead;
spaceAvailable -= bytesRead;
}
if (totalRead > 0) {
synchronized (bufferLock) {
buffer1Pending = true;
buffer1PendingLocation = nextLocation;
buffer1Length = totalRead;
nextLocation = -1; // assume next write is contiguous unless seeked
// Notify availability to write thread
if (DEBUG)
System.err.println("Notifying consumer");
bufferLock.notifyAll();
}
}
// Send EOS if necessary
if (bytesRead == -1) {
if (DEBUG) System.err.println("Got EOS");
receivedEOS = true;
}
}
}
/**
* Asynchronous write thread
*/
public void run() {
while (!(state == CLOSED)){
if(state==STARTED){
synchronized (bufferLock) {
// Wait for some data or error
while (!buffer1Pending && !buffer2Pending &&
state != CLOSED && !receivedEOS) {
if (DEBUG)
System.err.println("Waiting for filled buffer");
try {
bufferLock.wait(500);
} catch (InterruptedException ie) {
}
if (DEBUG)
System.err.println("Consumer notified");
}
}
// Something's pending
if (buffer2Pending) {
if (DEBUG)
System.err.println("Writing Buffer2");
// write that first
write(buffer2, buffer2PendingLocation, buffer2Length);
if (DEBUG)
System.err.println("Done writing Buffer2");
buffer2Pending = false;
}
synchronized (bufferLock) {
if (buffer1Pending) {
byte [] tempBuffer = buffer2;
buffer2 = buffer1;
buffer2Pending = true;
buffer2PendingLocation = buffer1PendingLocation;
buffer2Length = buffer1Length;
buffer1Pending = false;
buffer1 = tempBuffer;
if (DEBUG) System.err.println("Notifying producer");
bufferLock.notifyAll();
} else {
if (receivedEOS)
break;
}
}
}
if (receivedEOS) {
if (DEBUG)
System.err.println("Sending EOS: streamingEnabled is " + streamingEnabled);
if (!streamingEnabled) {
sendEndofStreamEvent();
}
}
}
}
/**
* seek a specific location in the dataSource
* @return the location where the data source is now placed
*/
public synchronized long seek(long where) {
nextLocation = where;
return where;
}
/**
* Write the data in parameter in the data source handler buffer
* @param buffer - data to write into the data source handler buffer
* @param location - location to start
* @param length - length to write
*/
private void write(byte [] buffer, long location, int length) {
int offset, toWrite;
offset = 0;
while (length > 0) {
toWrite = WRITE_CHUNK_SIZE;
if (length < toWrite)
toWrite = length;
baout.write(buffer, offset, toWrite);
bytesWritten += toWrite;
length -= toWrite;
offset += toWrite;
Thread.yield();
}
}
/**
* @see javax.media.DataSink#addDataSinkListener(javax.media.datasink.DataSinkListener)
*/
public void addDataSinkListener(DataSinkListener dsl) {
if (dsl != null)
if (!listeners.contains(dsl))
listeners.addElement(dsl);
}
/**
* @see javax.media.DataSink#removeDataSinkListener(javax.media.datasink.DataSinkListener)
*/
public void removeDataSinkListener(DataSinkListener dsl) {
if (dsl != null)
listeners.removeElement(dsl);
}
/**
* Send event to the listeners
* @param event - the vent to send
*/
protected void sendEvent(DataSinkEvent event) {
if (!listeners.isEmpty()) {
synchronized (listeners) {
Enumeration list = listeners.elements();
while (list.hasMoreElements()) {
DataSinkListener listener = (DataSinkListener)list.nextElement();
listener.dataSinkUpdate(event);
}
}
}
}
/**
* remove All the listeners from this data source handler
*/
protected void removeAllListeners() {
listeners.removeAllElements();
}
/**
* Send an end of stream event to the listeners
*/
protected final void sendEndofStreamEvent() {
sendEvent(new EndOfStreamEvent(this));
}
/**
* Send a data sink error event to the listeners
* @param reason - the reason of the error
*/
protected final void sendDataSinkErrorEvent(String reason) {
sendEvent(new DataSinkErrorEvent(this, reason));
}
/**
* Get the recorded buffer of this data source handler
* @return byte array containing the data recorded
*/
public byte[] getRecordBuffer(){
byte[] recordedBuffer= baout.toByteArray();
baout.reset();
return recordedBuffer;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -