Package com.sun.media.sound

Source Code of com.sun.media.sound.SimpleInputDevice

/*
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
*/

/*
* @(#)SimpleInputDevice.java   1.48 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

package com.sun.media.sound;

import java.util.Vector;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioPermission;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Control;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Port;
import javax.sound.sampled.TargetDataLine;


/**
* Simple input device.  Contains mixer and data line functionality for
* simple wave-in input devices.
*
* @version 1.48, 03/01/23
* @author Kara Kytle
*/
class SimpleInputDevice extends AbstractMixer {


    // INSTANCE VARIABLES
    private AudioFormat format = null;
    private int bufferSize = AudioSystem.NOT_SPECIFIED;

    /**
     * The default buffer size, if none of AudioSystem.NOT_SPECIFIED is
     * specified as buffer size. The default is a half second
     */
    private static final int DEFAULT_BUFFER_TIME = 500; // milliseconds

    // INSTANCE PROPERTIES

    /**
     * Security Manager;
     */
    private JSSecurity jsSecurity;

    /**
     * Fixed set of ports available on the input device.
     */
    private Port[] ports;

    /**
     * true after we call the native stream start
     */
    private boolean implStarted = false;


    // CONSTRUCTOR


    SimpleInputDevice(SimpleInputDeviceProvider.InputDeviceInfo inputDeviceInfo) {

        // pass in Line.Info, mixer, controls
        super(inputDeviceInfo,            // Mixer.Info
              null,                       // Control[]
              null,                       // Line.Info[] sourceLineInfo
              null);                      // Line.Info[] targetLineInfo

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: constructor");

        // first get the Security Manger
        jsSecurity = JSSecurityManager.getJSSecurity();

        // initialize platform-specific values, and load the native library
        Platform.initialize();

        // query our target line format capabilities
        Vector formats = new Vector();
        nGetFormats( ((SimpleInputDeviceProvider.InputDeviceInfo)getMixerInfo()).getIndex(),
                     formats,
                     AudioFormat.Encoding.PCM_SIGNED,
                     AudioFormat.Encoding.PCM_UNSIGNED,
                     AudioFormat.Encoding.ULAW,
                     AudioFormat.Encoding.ALAW);

        // $$kk: 06.03.99: this is stupid; should store these as an array!!
        AudioFormat[] formatArray;
        synchronized(formats) {
            formatArray = new AudioFormat[formats.size()];
            for (int i = 0; i < formatArray.length; i++) {
                formatArray[i] = (AudioFormat)formats.elementAt(i);
            }
        }


        // $$kk: 05.31.99: need to figure this out!
        // set up the port info objects

        int numPorts = nGetNumPorts();
        sourceLineInfo = new Port.Info[numPorts];
        ports = new Port[numPorts];
        String name;

        for (int i = 0; i < numPorts; i++) {

            name = nGetPortName(i);
            sourceLineInfo[i] = getPortInfo(name);

            ports[i] = new InputDevicePort((Port.Info)sourceLineInfo[i], this, new Control[0]);
        }


        // set up the target line objects

        targetLineInfo = new DataLine.Info[1];

        targetLineInfo[0] = new DataLine.Info(TargetDataLine.class,
                                              formatArray,
                                              0,
                                              AudioSystem.NOT_SPECIFIED);


        // set the initial format as the best supported one

        // $$jb: 12.07.99: Fix for 4297115: NoSuchElementException thrown on
        // machines without capture devices.  Make sure that the formats
        // vector has elements before we set the initial format.

        if( formats.size() > 0 ) {
            format = (AudioFormat)formats.lastElement();
        } else {
            format = null;
        }

        if (Printer.trace) Printer.trace("<< SimpleInputDevice: constructor completed");
    }



    // ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS

    public Line getLine(Line.Info info) throws LineUnavailableException {

        Line.Info fullInfo = getLineInfo(info);

        if (fullInfo == null) {
            throw new IllegalArgumentException("Line unsupported: " + info);
        }

        if (fullInfo instanceof Port.Info) {

            for (int i = 0; i < ports.length; i++) {
                if (fullInfo.equals(ports[i].getLineInfo())) {
                    return ports[i];
                }
            }
        }

        if (fullInfo instanceof DataLine.Info) {

            DataLine.Info dataLineInfo = (DataLine.Info)fullInfo;
            AudioFormat[] dataLineInfoFormats = dataLineInfo.getFormats();

            if (dataLineInfoFormats.length == 0) {
                throw new IllegalArgumentException("Line unsupported: " + info);
            }
            if (dataLineInfo.getLineClass().isAssignableFrom(InputDeviceDataLine.class)) {

                int reqBufferSize = AudioSystem.NOT_SPECIFIED;
                AudioFormat reqFormat = null;

                // look for a requested format and buffer size
                if (info instanceof DataLine.Info) {

                    // look for a requested format

                    AudioFormat[] sFormats = ((DataLine.Info)info).getFormats();

                    if( (sFormats != null) && (sFormats.length > 0) ) {
                        reqFormat = sFormats[sFormats.length-1];
                    }


                    // look for a requested buffer size

                    reqBufferSize = ((DataLine.Info)info).getMaxBufferSize();

                    if (reqBufferSize == AudioSystem.NOT_SPECIFIED) {
                        reqBufferSize = ((DataLine.Info)info).getMinBufferSize();
                    }

                    if (reqBufferSize <= 0) {
                        reqBufferSize = AudioSystem.NOT_SPECIFIED;
                    }
                }


                // if no format requested, get the best supported format.
                if (reqFormat == null) {
                    reqFormat = dataLineInfoFormats[dataLineInfoFormats.length-1];
                }

                // if no buffer size requested, calculate one
                if (reqBufferSize == AudioSystem.NOT_SPECIFIED) {
                    // we are counting in bytes here
                    reqBufferSize = (int) Toolkit.millis2bytes(reqFormat, DEFAULT_BUFFER_TIME);
                }

                return new InputDeviceDataLine(dataLineInfo, this, reqFormat, reqBufferSize);
            }
        }

        throw new IllegalArgumentException("Line unsupported: " + info);
    }


    public int getMaxLines(Line.Info info) {

        Line.Info fullInfo = getLineInfo(info);


        // if it's not supported at all, return 0.
        if (fullInfo == null) {
            return 0;
        }


        // $$kk: 06.02.99: for ports, let's assume we can only have one capture
        // port open at a time.  the real situation may be more complicated.
        if (fullInfo instanceof Port.Info) {
            return 1;
        }


        // $$kk: 06.02.99: any number!
        if (fullInfo instanceof DataLine.Info) {
            return AudioSystem.NOT_SPECIFIED;
        }

        return 0;
    }


    public void implOpen() throws LineUnavailableException {
        // check for record permission
        if( jsSecurity != null ) {
            jsSecurity.checkRecordPermission();
        }

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: implOpen");


        // if bufferSize is less than zero (e.g. UNSPECIFIED), set it to
        // 0, which will use the default buffer size in the native code.
        if( bufferSize < 0 ) {
            bufferSize = 0;
        }

        // $$kk: 08.04.99 trying this....  the java buffer is the largest;
        // data can be written to and read from it in pieces.  since read
        // and write block, this allows us to avoid a fast-or-famine buffer
        // lifestyle.
        int bufferSizeDivisor = 8;

        // translate the encoding into a magic number
        int encoding = PCM;
        if (format.getEncoding() == AudioFormat.Encoding.ULAW) {
            encoding = ULAW;
        } else if (format.getEncoding() == AudioFormat.Encoding.ALAW) {
            encoding = ALAW;
        }

        // open the capture device
        // note that this method takes the buffer size in frames
        nOpen(((SimpleInputDeviceProvider.InputDeviceInfo)getMixerInfo()).getIndex(),
              encoding,
              (int)format.getSampleRate(),
              format.getSampleSizeInBits(),
              format.getChannels(),
              (bufferSize / (format.getFrameSize() * bufferSizeDivisor))
              );

        // update the format and buffer size values.
        // (buffer size may differ from requested value.)
        //this.format = format;
        this.bufferSize = nGetBufferSizeInFrames() * format.getFrameSize() * bufferSizeDivisor;

        if (Printer.trace) Printer.trace("<< SimpleInputDevice: implOpen succeeded. Format="+format+"  buffersize="+bufferSize);
    }

    public void implClose() {

        // check for record permission
        if( jsSecurity != null ) {
            jsSecurity.checkRecordPermission();
        }

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: implClose");

        // close the capture device
        nClose();
        implStarted = false;

        if (Printer.trace) Printer.trace("<< SimpleInputDevice: implClose succeeded");
    }


    // ABSTRACT DATA LINE: ABSTRACT METHOD IMPLEMENTATIONS

    /**
     * Start the input device
     */
    protected void implStart() {

        // check for record permission
        if( jsSecurity != null ) {
            jsSecurity.checkRecordPermission();
        }

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: implStart");

        if (implStarted == false) {

            if (Printer.debug) Printer.debug("SimpleInputDevice: implStart: starting the device");
            nStart();
            implStarted = true;

        } else {

            if (Printer.debug) Printer.debug("SimpleInputDevice: implStart: resuming the device");
            nResume();
        }

        if (Printer.trace) Printer.trace("<< SimpleInputDevice: implStart succeeded");
    }


    /**
     * Stop the input device
     */
    protected void implStop() {

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: implStop");

        // check for record permission
        if( jsSecurity != null ) {
            jsSecurity.checkRecordPermission();
        }

        if (Printer.trace) Printer.trace(">> SimpleInputDevice: implStop");

        nPause();

        if (Printer.trace) Printer.trace("<< SimpleInputDevice: implStop succeeded");
    }


    // METHOD OVERRIDES


    /**
     * This implementation of this method determines whether
     * this line is a source or target line, calls open(format, bufferSize)
     * on the mixer, and adds the line to the appropriate vector.  The mixer
     * must be opened at the *same* *format* as the line is requesting.
     */
    /*
      protected void open(DataLine line, AudioFormat format, int bufferSize) throws LineUnavailableException {

      if (Printer.trace) Printer.trace(">> AbstractMixer: open(line = " + line + ")");

      // $$kk: 06.11.99: ignore ourselves for now
      if (this.equals(line)) {
      return;
      }

      // source line?
      if (isSourceLine(line.getLineInfo())) {

      if (! sourceLines.contains(line) ) {

      // call the no-arg open method for the mixer; it should open at its
      // default format if it is not open yet
      open(format, bufferSize);

      // we opened successfully!  add the line to the list
      sourceLines.addElement(line);
      }
      } else {

      // target line?
      if(isTargetLine(line.getLineInfo())) {

      if (! targetLines.contains(line) ) {

      // call the no-arg open method for the mixer; it should open at its
      // default format if it is not open yet
      open(format, bufferSize);

      // we opened successfully!  add the line to the list
      targetLines.addElement(line);
      }
      } else {
      if (Printer.err) Printer.err("Unknown line received for AbstractMixer.open(Line): " + line);
      }
      }

      if (Printer.trace) Printer.trace("<< AbstractMixer: open(line, format, bufferSize) completed");
      }
    */

    // HELPER METHODS


    /**
     * Utility method for converting between String names and well-known
     * Port types.  I'm only doing the ones that can be sources.  We may
     * want to do something at least a little more general here....
     */
    private Port.Info getPortInfo(String name) {

        if (name.equals(Port.Info.MICROPHONE.toString())) {
            return Port.Info.MICROPHONE;
        }

        if (name.equals(Port.Info.LINE_IN.toString())) {
            return Port.Info.LINE_IN;
        }

        if (name.equals(Port.Info.COMPACT_DISC.toString())) {
            return Port.Info.COMPACT_DISC;
        }

        // return a new port info object.
        return (new InputDevicePortInfo(name));
    }



    // INPUT DEVICE METHODS


    // CALLBACKS

    private void callbackCaptureStreamDestroy() {

        if (Printer.debug) Printer.debug("SimpleInputDevice: callbackCaptureStreamDestroy");

        /* do we even need this callback? */
    }


    private void callbackStreamPutData(byte[] data, int lengthInFrames) {

        if (Printer.verbose) Printer.verbose(">> SimpleInputDevice: callbackStreamPutData: data: " + data + " data.length: " + data.length + " lengthInFrames: " + lengthInFrames);

        // write the captured data to the circular buffer for each open, running target data line
        int lengthInBytes = lengthInFrames * format.getFrameSize();
        InputDeviceDataLine targetLine = null;
        Vector lines = null;

        synchronized (targetLines) {
            if (targetLines.size() == 1) {
                // optimization for the most-often case
                targetLine = (InputDeviceDataLine)targetLines.elementAt(0);
            } else {
                // we need to clone the vector to prevent simultaneous locking
                // of targetLines and one of the lines itself - this caused deadlock
                lines = (Vector) targetLines.clone();
            }
        }
        if (targetLine != null) {
            targetLine.fillBuffer(data, lengthInBytes);
        } else {
            for (int i = 0; i < targetLines.size(); i++) {
                targetLine = (InputDeviceDataLine)targetLines.elementAt(i);
                targetLine.fillBuffer(data, lengthInBytes);
            }
        }

        if (Printer.verbose) Printer.verbose("<< SimpleInputDevice: callbackStreamPutData completed");
    }


    // INNER CLASSES

    /**
     * Private inner class representing the target data line for the SimpleInputDevice.
     */
    private static class InputDeviceDataLine extends AbstractDataLine implements TargetDataLine {

        private CircularBuffer circularBuffer = null;
        private SimpleInputDevice sid;


        // CONSTRUCTOR

        private InputDeviceDataLine(DataLine.Info info,
                                    SimpleInputDevice mixer,
                                    AudioFormat initialFormat,
                                    int initialBufferSize) {

            // $$kk: 06.02.99: need to deal with controls!
            super(info, mixer, null, initialFormat, initialBufferSize);

            if (Printer.trace) Printer.trace("InputDeviceDataLine CONSTRUCTOR: info: " + info + " initialFormat: " + initialFormat + " initialBufferSize: " + initialBufferSize);
            this.sid = mixer;
        }


        // TARGET DATA LINE METHODS

        public int read(byte[] b, int off, int len) {

            if (Printer.verbose) Printer.verbose("> InputDeviceDataLine.read(b.length: " + b.length + " off: " + off + " len: " + len);

            int totalBytesToRead = len;

            if (len % getFormat().getFrameSize() != 0) {
                throw new IllegalArgumentException("Illegal request to write non-integral number of frames (" + len + " bytes )");
            }

            int totalBytesRead = 0;
            int currentBytesRead = 0;

            // $$kk: 08.17.99: changed this to return if not running as well as if not open
            while (isOpen() && (totalBytesRead < totalBytesToRead)) {
                if (!isStartedRunning()) {
                    Thread.yield();
                    break;
                }

                currentBytesRead = circularBuffer.read(b, off, (totalBytesToRead - totalBytesRead));
                totalBytesRead += currentBytesRead;
                off += currentBytesRead;

                if (totalBytesRead < totalBytesToRead) {
                    try {
                        synchronized(this) {
                            // $$kk: 08.17.99: need to make sure we never block forever here!
                            wait();
                        }
                    } catch (InterruptedException e) {
                    }
                }
            }

            if (Printer.verbose) Printer.verbose("< InputDeviceDataLine.read returning: " + totalBytesRead);
            return totalBytesRead;
        }


        public int available() {
            return circularBuffer.bytesAvailableToRead();
        }


        // ABSTRACT METHOD IMPLEMENTATIONS

        // ABSTRACT LINE

        void implOpen(AudioFormat format, int bufferSize) throws LineUnavailableException {

            if (Printer.trace) Printer.trace(">> InputDeviceDataLine: implOpen");

            // check for record permission
            if( sid.jsSecurity != null ) {
                sid.jsSecurity.checkRecordPermission();
            }


            // set default buffer size, if not specified
            // fix for bug 4769277: REGRESSION:jck14a:api/javax_sound/sampled/Mixer/index.html#getTargetLines fails
            if (bufferSize < 0 || bufferSize == AudioSystem.NOT_SPECIFIED) {
                // we are counting in bytes here
                bufferSize = (int) Toolkit.millis2bytes(format, DEFAULT_BUFFER_TIME);
            }


            // reset local buffersize to the buffer size of the mixer
            // this is necessary in case the native code could not set the
            // buffer size to the requested buffer size
            // note: this method is called after mixer.implOpen was called!
            //bufferSize = sid.bufferSize;

            // only allow a new instance if the format is compatible with the already established format
            checkFormat(format);


            // figure out the signed/unsigned and big/little endian conversions

            boolean convertSign = false;
            boolean convertByteOrder = false;

            if ( (format.getSampleSizeInBits() <= 8) && ( (format.getEncoding() == AudioFormat.Encoding.PCM_SIGNED) && (Platform.isSigned8() == false) ) ) {
                convertSign = true;
            } else if ( (format.getSampleSizeInBits() <= 8) && ( (format.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED) && (Platform.isSigned8() == true) ) ) {
                convertSign = true;
            }

            if ( (format.getSampleSizeInBits() > 8) && (format.isBigEndian() != Platform.isBigEndian()) ) {
                convertByteOrder = true;
            }


            // create the circular buffer
            circularBuffer = new CircularBuffer(bufferSize, convertSign, convertByteOrder);

            // set the bufferSize and format variables for the line
            this.bufferSize = bufferSize;
            this.format = format;

            if (Printer.trace) Printer.trace("<< InputDeviceDataLine: implOpen succeeded");
        }


        void implClose() {

            if (Printer.trace) Printer.trace(">> InputDeviceDataLine: implClose()");

            // check for record permission
            if( sid.jsSecurity != null ) {
                sid.jsSecurity.checkRecordPermission();
            }

            if (Printer.trace) Printer.trace("<< InputDeviceDataLine: implClose() succeeded");
        }


        // ABSTRACT DATA LINE

        /**
         * Call the superclass open() method, which will try to open
         * the line with the current format and buffer size values.
         * If this fails,  try to open the line with the current
         * system format.
         */
        public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
            // if the mixer is not yet opened, set format and buffer size
            if (!mixer.isOpen()) {
                sid.format = format;
                sid.bufferSize = bufferSize;
            }
            super.open(format, bufferSize);
        }

        void implStart() {

            if (Printer.trace) Printer.trace(">> InputDeviceDataLine: implStart");

            // check for record permission
            if( sid.jsSecurity != null ) {
                sid.jsSecurity.checkRecordPermission();
            }

            if (Printer.trace) Printer.trace("<< InputDeviceDataLine: implStart succeeded");
        }


        void implStop() {

            // check for record permission
            if( sid.jsSecurity != null ) {
                sid.jsSecurity.checkRecordPermission();
            }

            if (Printer.trace) Printer.trace(">> InputDeviceDataLine: implStop");

            // set active false
            setActive(false);
            setStarted(false);

            if (Printer.trace) Printer.trace("<< InputDeviceDataLine: implStop succeeded");
        }


        // METHOD OVERRIDES


        public void drain() {

            if (isOpen()) {

                // drain data from the circular buffer
                circularBuffer.drain();

                // drain the native buffers
                sid.nDrain();
            }
        }


        public void flush() {

            if (isOpen()) {

                // flush data from the circular buffer
                circularBuffer.flush();

                // flush the native buffers
                sid.nFlush();
            }
        }


        public int getFramePosition() {
            return (isOpen()) ? (int)sid.nGetPosition() : super.getFramePosition();
        }


        // METHODS FOR INTERNAL IMPLEMENTATION USE
        private void fillBuffer(byte[] data, int lengthInBytes) {
            if (isOpen() && isStartedRunning()) {
                // set active true
                if (!isActive()) {
                    setActive(true);
                    setStarted(true);
                }

                // this will write the current data over old data if the amount of new data
                // exceeds the amount of available space in the circular buffer.
                // $$kk: 08.04.99: we can dump data here.  should have overflow event / exception /
                // notification mechanism?
                int bytesDumped = circularBuffer.writeover(data, 0, lengthInBytes);

                synchronized(this) {
                    notifyAll();
                }

                if (bytesDumped > 0) {
                    if (Printer.debug) Printer.debug("fillBuffer: buffer overflow for line " + this + "!  received " + lengthInBytes + " bytes, dumped " + bytesDumped);
                }
            }
        }

        private void checkFormat(AudioFormat format) throws LineUnavailableException {
            if (sid.isOpen()) {
                AudioFormat.Encoding enc1 = format.getEncoding();
                AudioFormat.Encoding enc2 = sid.format.getEncoding();
                boolean ok = (enc1.equals(AudioFormat.Encoding.PCM_SIGNED) && enc2.equals(AudioFormat.Encoding.PCM_UNSIGNED))
                    || (enc2.equals(AudioFormat.Encoding.PCM_SIGNED) && enc1.equals(AudioFormat.Encoding.PCM_UNSIGNED))
                    || enc1.equals(enc2);
                if (ok) {
                    // the rest - except endianness - just has to match
                    format = new AudioFormat(enc2,
                                             format.getSampleRate(),
                                             format.getSampleSizeInBits(),
                                             format.getChannels(),
                                             format.getFrameSize(),
                                             format.getFrameRate(),
                                             sid.format.isBigEndian());
                }
                if (!ok || !format.matches(sid.format)) {
                    throw new LineUnavailableException("Requested format incompatible with already established device format: " + sid.format);
                }
            }
        }


    } // class InputDeviceDataLine


    /**
     * Private inner class representing a port on the input device.
     */
    private class InputDevicePort extends AbstractLine implements Port {

        private InputDevicePort(Port.Info info, AbstractMixer mixer, Control[] controls) {
            super(info, mixer, controls);
        }


        public synchronized void open() throws LineUnavailableException {

            if (!isOpen()) {

                // check for record permission
                if( jsSecurity != null ) {
                    jsSecurity.checkRecordPermission();
                }

                // allocate mixer resources
                mixer.open(this);

                /* $$kk: 06.03.99: need to implement native open */

                // mark the line open and send events
                setOpen(true);
            }
        }


        //public synchronized void implClose() {
        public synchronized void close() {

            if (isOpen()) {

                // check for record permission
                if( jsSecurity != null ) {
                    jsSecurity.checkRecordPermission();
                }


                /* $$kk: 06.03.99: need to implement native open */

                // mark the line closed and send events
                setOpen(false);

                // release mixer resources
                mixer.close(this);
            }
        }
    } // class InputDevicePort


    /**
     * Private inner class representing an input device port info
     */
    private static class InputDevicePortInfo extends Port.Info {

        private InputDevicePortInfo(String name) {
            super(Port.class, name, true);
        }
    }





    // NATIVE METHODS

    // gets the set of formats supported by the capture device with this index
    private native void nGetFormats(int index, Vector formats,
                                    AudioFormat.Encoding pcm_signed,
                                    AudioFormat.Encoding pcm_unsigned,
                                    AudioFormat.Encoding ulaw,
                                    AudioFormat.Encoding alaw);

    // this will open the capture device and create the native stream object
    // HAE_AquireAudioCapture and GM_AudioCaptureStreamSetup
    // note that this takes the buffer size in frames.
    private native void nOpen(int index, int encoding, float sampleRate,
                              int sampleSizeInBits, int channels,
                              int bufferSize) throws LineUnavailableException;

    // GM_AudioCaptureStreamCleanup
    // calls GM_AudioCaptureStreamStop and then frees the stream
    private native void nClose();

    // GM_AudioCaptureStreamStart
    // this will allocate the buffers and create and start the capture thread
    // we do this on the first start() call
    private native void nStart();

    // GM_AudioCaptureStreamStop
    // this will deallocate the buffers and stop the capture thread.
    // $$kk: 06.13.99: need to make this call as part of close!!
    // otherwise we can crash in a callback!!  i'll leave the commented-out
    // method in cause we need it from java later....
    // private native void nStop();

    // HAE_PauseAudioCapture
    // we use this for stop(); it stops active capture but does not release the device
    private native void nPause();

    // HAE_ResumeAudioCapture
    // we use this for start(); it start active capture but does not affect the device
    private native void nResume();

    // these don't work
    private native void nDrain();
    private native void nFlush();

    // returns the frames captured at the device
    private native long nGetPosition();

    // gets the native capture buffer size in sample frames
    private native int nGetBufferSizeInFrames();

    // gets the number of ports
    private native int nGetNumPorts();

    // gets the name of the port with this index
    private native String nGetPortName(int index);
}
TOP

Related Classes of com.sun.media.sound.SimpleInputDevice

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');