FileDocCategorySizeDatePackage
JavaSoundSourceStream.javaAPI DocJMF 2.1.1e19497Mon May 12 12:20:54 BST 2003com.sun.media.protocol.javasound

JavaSoundSourceStream

public class JavaSoundSourceStream extends BasicSourceStream implements PushBufferStream
JavaSound capture stream.

Fields Summary
DataSource
dsource
TargetDataLine
dataLine
javax.media.format.AudioFormat
format
javax.media.format.AudioFormat
devFormat
boolean
reconnect
int
bufSize
BufferTransferHandler
transferHandler
boolean
started
com.sun.media.ui.AudioFormatChooser
afc
BufferControl
bc
com.sun.media.CircularBuffer
cb
PushThread
pushThread
static int
DefRate
static int
DefBits
static int
DefChannels
static int
DefSigned
static int
DefEndian
static int
OtherEndian
static javax.media.Format[]
supported
protected static CaptureDeviceInfo[]
deviceList
private static com.sun.media.JMFSecurity
jmfSecurity
private static boolean
securityPrivelege
private Method[]
mSecurity
private Class[]
clSecurity
private Object[]
argsSecurity
static int
DefaultMinBufferSize
static int
DefaultMaxBufferSize
long
bufLenReq
Constructors Summary
public JavaSoundSourceStream(DataSource ds)


     

	try {
	    jmfSecurity = JMFSecurityManager.getJMFSecurity();
	    securityPrivelege = true;
	} catch (SecurityException e) {
	}

	supported = new javax.media.Format[] {

		// The first one is the default.
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			44100,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			2,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			44100,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			1,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			22050,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			2,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			22050,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			1,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			11025,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			2,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			11025,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			1,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			8000,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			2,
			DefEndian,
			DefSigned),
		new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			8000,
			16, //javax.media.format.AudioFormat.NOT_SPECIFIED,
			1,
			DefEndian,
			DefSigned),
	};

	deviceList = new CaptureDeviceInfo [] {
		   	    new CaptureDeviceInfo("JavaSound audio capture",
			    new MediaLocator("javasound://44100"), 
			    supported)
		     };
    
	super(new ContentDescriptor(ContentDescriptor.RAW), LENGTH_UNKNOWN);
	dsource = ds;


	bc = new BC(this);

	controls = new javax.media.Control[2];
	controls[0] = new FC(this);
	controls[1] = bc;
    
Methods Summary
public voidconnect()
Connect to the device. It in turn calls openDev to do the real work.


	// Return if it's already connected.
	if (isConnected())
	    return;

	if (JavaSoundOutput.isOpen()) {
	    Log.warning("JavaSound is already opened for rendering.  Will capture at the default format.");
	    format = null;
	}

	openDev();

	if (pushThread == null) {

	    if ( /*securityPrivelege  && */ (jmfSecurity != null) ) {
		String permission = null;
		try {
		    if (jmfSecurity.getName().startsWith("jmf-security")) {
			permission = "thread";
			jmfSecurity.requestPermission(mSecurity, clSecurity, argsSecurity,
						  JMFSecurity.THREAD);
			mSecurity[0].invoke(clSecurity[0], argsSecurity[0]);
		    
			permission = "thread group";
			jmfSecurity.requestPermission(mSecurity, clSecurity, argsSecurity,
						  JMFSecurity.THREAD_GROUP);
			mSecurity[0].invoke(clSecurity[0], argsSecurity[0]);
		    } else if (jmfSecurity.getName().startsWith("internet")) {
			PolicyEngine.checkPermission(PermissionID.THREAD);
			PolicyEngine.assertPermission(PermissionID.THREAD);
		    }
		} catch (Throwable e) {
		    if (JMFSecurityManager.DEBUG) {
			System.err.println( "Unable to get " + permission +
					" privilege  " + e);
		    }
		    securityPrivelege = false;
		    // TODO: Do the right thing if permissions cannot 
		    // be obtained.
		    // User should be notified via an event
		}
	    }
	
	    if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) {
		try {
		    Constructor cons = jdk12CreateThreadAction.cons;
		
		    pushThread = (PushThread) jdk12.doPrivM.invoke(
                                           jdk12.ac,
					   new Object[] {
 					  cons.newInstance(
 					   new Object[] {
                                               PushThread.class,
                                           })});
		} catch (Exception e) {
		    // System.out.println("Exception: creating pushThread");
		}
	    } else {
		pushThread = new PushThread();
	    }

	    pushThread.setSourceStream(this);
	}

	if (reconnect)
	    Log.comment("Capture buffer size: " + bufSize);
	devFormat = format;
	reconnect = false;
    
public voiddisconnect()

	if (dataLine == null)
	    return;
	/*
	dataLine.drain();
	*/
	dataLine.stop();
	dataLine.close();

	dataLine = null;
	devFormat = null;
	if (pushThread != null) {
	    pushThread.kill();
	    pushThread = null;
	}
    
public java.lang.Object[]getControls()

	return controls;
    
public javax.media.FormatgetFormat()

	return format;
    
public static javax.media.Format[]getSupportedFormats()

	return supported;
    
public booleanisConnected()

	return devFormat != null;
    
public static CaptureDeviceInfo[]listCaptureDeviceInfo()

	return deviceList;
    
voidopenDev()
Open the capture device.


	DataLine.Info info;
	javax.sound.sampled.AudioFormat afmt = null;

	if (format != null) {

	    afmt = JavaSoundOutput.convertFormat(format);
	    int chnls = (format.getChannels() == 
			    javax.media.format.AudioFormat.NOT_SPECIFIED ?
					1 : format.getChannels()); 
	    int size = (format.getSampleSizeInBits() == 
			    javax.media.format.AudioFormat.NOT_SPECIFIED ?
					16 : format.getSampleSizeInBits()); 
	    int frameSize = (size * chnls)/8;

	    if (frameSize  == 0)
		frameSize = 1;

	    bufSize = (int)(format.getSampleRate() * frameSize *
					bc.getBufferLength() / 1000);

	    info = new DataLine.Info(TargetDataLine.class, afmt, bufSize);
	} else {
	    info = new DataLine.Info(TargetDataLine.class,
				null, AudioSystem.NOT_SPECIFIED);
	}

	if (!AudioSystem.isLineSupported(info)) {
	    Log.error("Audio not supported: " + info + "\n");
	    throw new IOException("Cannot open audio device for input.");
	}

	try {

	    dataLine = (TargetDataLine)AudioSystem.getLine(info);

	    if (format != null) {
		dataLine.open(afmt, bufSize);
	    } else {
		dataLine.open();
		format = JavaSoundOutput.convertFormat(dataLine.getFormat());
	    }

	    bufSize = dataLine.getBufferSize();

	    //dataLine.start();

	} catch (Exception e) {
	    Log.error("Cannot open audio device for input: " + e);
	    throw new IOException(e.getMessage());
	}
    
public static javax.media.FormatparseLocator(MediaLocator ml)
Parse the javasound media locator which specifies the format. A valid media locator is of the form: javasound://[rate]/[sizeInBits]/[channels]/[big|little]/[signed|unsigned]


	int rate, bits, channels, endian, signed;

	String rateStr = null, bitsStr = null, channelsStr = null;
	String endianStr = null, signedStr = null;

	// Parser the media locator to extract the requested format.

	String remainder = ml.getRemainder();
	if (remainder != null && remainder.length() > 0) {
	    while (remainder.length() > 1 && remainder.charAt(0) == '/")
		remainder = remainder.substring(1);
	    // Now see if there's a sample rate specified.
	    int off = remainder.indexOf('/");
	    if (off == -1) {
		if (!remainder.equals(""))
		    rateStr = remainder;
	    } else {
		rateStr = remainder.substring(0, off);
		remainder = remainder.substring(off + 1);
		// Now see if there's a sample size specified
		off = remainder.indexOf('/");
		if (off == -1) {
		    if (!remainder.equals(""))
			bitsStr = remainder;
		} else {
		    bitsStr = remainder.substring(0, off);
		    remainder = remainder.substring(off + 1);
		    // Now see if there's a channels specified
		    off = remainder.indexOf('/");
		    if (off == -1) {
			if (!remainder.equals(""))
			    channelsStr = remainder;
		    } else {
			channelsStr = remainder.substring(0, off);
			remainder = remainder.substring(off + 1);
			// Now see if there's endian specified.
			off = remainder.indexOf('/");
			if (off == -1) {
			    if (!remainder.equals(""))
				endianStr = remainder;
			} else {
			    endianStr = remainder.substring(0, off);
			    if (!remainder.equals(""))
			        signedStr = remainder.substring(off + 1);
			}
		   }
		}
	    }
	}

	// Sample Rate
	rate = DefRate;
	if (rateStr != null) {
	    try {
		Integer integer = Integer.valueOf(rateStr);
		if (integer != null)
		    rate = integer.intValue();
	    } catch (Throwable t) { }

	    // Range check.
	    if (rate <= 0 || rate > 96000) {
		Log.warning("JavaSound capture: unsupported sample rate: " + rate);
		rate = DefRate;
		Log.warning("        defaults to: " + rate);
	    }
	}

	// Sample Size
	bits = DefBits;
	if (bitsStr != null) {
	    try {
		Integer integer = Integer.valueOf(bitsStr);
		if (integer != null)
		    bits = integer.intValue();
	    } catch (Throwable t) { }

	    // Range check.
	    if (bits != 8 && bits != 16) {
		Log.warning("JavaSound capture: unsupported sample size: " + bits);
		bits = DefBits;
		Log.warning("        defaults to: " + bits);
	    }
	}

	// # of channels
	channels = DefChannels;
	if (channelsStr != null) {
	    try {
		Integer integer = Integer.valueOf(channelsStr);
		if (integer != null)
		    channels = integer.intValue();
	    } catch (Throwable t) { }

	    // Range check.
	    if (channels != 1 && channels != 2) {
		Log.warning("JavaSound capture: unsupported # of channels: " + channels);
		channels = DefChannels;
		Log.warning("        defaults to: " + channels);
	    }
	}

	// Endian
    	endian = DefEndian;
	if (endianStr != null) {
	    if (endianStr.equalsIgnoreCase("big"))
    		endian = javax.media.format.AudioFormat.BIG_ENDIAN;
	    else if (endianStr.equalsIgnoreCase("little"))
		endian = javax.media.format.AudioFormat.LITTLE_ENDIAN;
	    else {
		Log.warning("JavaSound capture: unsupported endianess: " + endianStr);
		Log.warning("        defaults to: big endian");
	    }
	}

	// Signed
    	signed = DefSigned;
	if (signedStr != null) {
	    if (signedStr.equalsIgnoreCase("signed"))
		signed = javax.media.format.AudioFormat.SIGNED;
	    else if (signedStr.equalsIgnoreCase("unsigned"))
    		signed = javax.media.format.AudioFormat.UNSIGNED;
	    else {
		Log.warning("JavaSound capture: unsupported signedness: " + signedStr);
		Log.warning("        defaults to: signed");
	    }
	}

	javax.media.format.AudioFormat fmt;
	fmt = new javax.media.format.AudioFormat(
			javax.media.format.AudioFormat.LINEAR,
			rate, bits, channels, endian, signed);

	return fmt;
    
public voidread(Buffer in)


	Buffer buffer;
	Object data;

	synchronized (cb) {
	    while (!cb.canRead()) {
		try {
		   cb.wait();
		} catch (Exception e) {}
	    }
	    buffer = cb.read();
	}

	// Swap data with the input buffer and my own buffer.
	data = in.getData();
	in.copy(buffer);
	buffer.setData(data);

	synchronized (cb) {
	    cb.readReport();
	    cb.notify();
	}
    
public javax.media.FormatsetFormat(javax.media.Format fmt)
Set the capture format.


	if (started) {
	    Log.warning("Cannot change audio capture format after started.");
	    return format;
	}

	if (fmt == null)
	    return format;

	javax.media.Format f = null;
	for (int i = 0; i < supported.length; i++) {
	    if (fmt.matches(supported[i]) &&
		(f = fmt.intersects(supported[i])) != null) {
		break;
	    }
	}

	if (f == null)
	    return format;

	try {
	    if (devFormat != null) {

		if (!devFormat.matches(f) && !JavaSoundOutput.isOpen()) {
		    // Can't change format if JavaSound is already opened
		    // for rendering.

		    //System.err.println("The capture format has changed.");
		    format = (javax.media.format.AudioFormat)f;
		    disconnect();
		    connect();
		}
	    } else {
		format = (javax.media.format.AudioFormat)f;
		connect();
	    }
	} catch (IOException e) {
	    return null;
	}

	if (afc != null)
	   afc.setCurrentFormat(format);

	return format;
    
public voidsetTransferHandler(BufferTransferHandler th)

	transferHandler = th;
    
public voidstart()
Start capturing.

	if (dataLine == null)
	    throw new IOException("A JavaSound input channel cannot be opened.");
	if (started)
	    return;

	// Check if the GUI control has specified a new format.
	if (afc != null) {
	    Format f;
	    if ((f = afc.getFormat()) != null && !f.matches(format)) {
		if (setFormat(f) == null) {
		    //System.err.println("The chosen format is not supported.");
		}
	    }
	    afc.setEnabled(false);
	}

	// Disconnect the source if the reconnect flag is on.
	if (reconnect)
	    disconnect();

	// Connect the source if it's not already connected.
	if (!isConnected())
	    connect();

	// Flush the old data.
	synchronized (cb) {
	    while (cb.canRead()) {
		cb.read();
		cb.readReport();
	    }
	    cb.notifyAll();
	}

	pushThread.start();
	dataLine.flush();
	dataLine.start();
	started = true;
    
public voidstop()
Stop the capture.

	if (!started)
	    return;

	pushThread.pause();
	if (dataLine != null)
	    dataLine.stop();
	started = false;
	if (afc != null && !JavaSoundOutput.isOpen())
	    afc.setEnabled(true);
    
public booleanwillReadBlock()

	return !started;