001package org.intellimate.izou.system.sound;
002
003import org.intellimate.izou.addon.AddOnModel;
004import org.intellimate.izou.main.Main;
005
006import javax.sound.sampled.AudioFormat;
007import javax.sound.sampled.LineUnavailableException;
008import javax.sound.sampled.SourceDataLine;
009
010/**
011 * the delegation to SourceDataLine.
012 * @author LeanderK
013 * @version 1.0
014 */
015public class IzouSoundSourceDataLine extends IzouSoundDataLine implements SourceDataLine {
016    private final SourceDataLine sourceDataLine;
017
018    public IzouSoundSourceDataLine(SourceDataLine dataLine, Main main, boolean isPermanent, AddOnModel addOnModel) {
019        super(dataLine, main, isPermanent, addOnModel);
020        this.sourceDataLine = dataLine;
021    }
022
023    /**
024     * Opens the line with the specified format and suggested buffer size,
025     * causing the line to acquire any required
026     * system resources and become operational.
027     * <p>
028     * The buffer size is specified in bytes, but must represent an integral
029     * number of sample frames.  Invoking this method with a requested buffer
030     * size that does not meet this requirement may result in an
031     * IllegalArgumentException.  The actual buffer size for the open line may
032     * differ from the requested buffer size.  The value actually set may be
033     * queried by subsequently calling <code>DataLine#getBufferSize</code>.
034     * <p>
035     * If this operation succeeds, the line is marked as open, and an
036     * <code>LineEvent.Type#OPEN OPEN</code> event is dispatched to the
037     * line's listeners.
038     * <p>
039     * Invoking this method on a line which is already open is illegal
040     * and may result in an <code>IllegalStateException</code>.
041     * <p>
042     * Note that some lines, once closed, cannot be reopened.  Attempts
043     * to reopen such a line will always result in a
044     * <code>LineUnavailableException</code>.
045     *
046     * @param format the desired audio format
047     * @param bufferSize the desired buffer size
048     * @throws LineUnavailableException if the line cannot be
049     * opened due to resource restrictions
050     * @throws IllegalArgumentException if the buffer size does not represent
051     * an integral number of sample frames,
052     * or if <code>format</code> is not fully specified or invalid
053     * @throws IllegalStateException if the line is already open
054     * @throws SecurityException if the line cannot be
055     * opened due to security restrictions
056     *
057     * @see #open(AudioFormat)
058     */
059    @Override
060    public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
061        opening();
062        sourceDataLine.open(format, bufferSize);
063    }
064
065    /**
066     * Opens the line with the specified format, causing the line to acquire any
067     * required system resources and become operational.
068     *
069     * <p>
070     * The implementation chooses a buffer size, which is measured in bytes but
071     * which encompasses an integral number of sample frames.  The buffer size
072     * that the system has chosen may be queried by subsequently calling
073     * <code>DataLine#getBufferSize</code>.
074     * <p>
075     * If this operation succeeds, the line is marked as open, and an
076     * <code>LineEvent.Type#OPEN OPEN</code> event is dispatched to the
077     * line's listeners.
078     * <p>
079     * Invoking this method on a line which is already open is illegal
080     * and may result in an <code>IllegalStateException</code>.
081     * <p>
082     * Note that some lines, once closed, cannot be reopened.  Attempts
083     * to reopen such a line will always result in a
084     * <code>LineUnavailableException</code>.
085     *
086     * @param format the desired audio format
087     * @throws LineUnavailableException if the line cannot be
088     * opened due to resource restrictions
089     * @throws IllegalArgumentException if <code>format</code>
090     * is not fully specified or invalid
091     * @throws IllegalStateException if the line is already open
092     * @throws SecurityException if the line cannot be
093     * opened due to security restrictions
094     *
095     * @see #open(AudioFormat, int)
096     */
097    @Override
098    public void open(AudioFormat format) throws LineUnavailableException {
099        opening();
100        sourceDataLine.open(format);
101    }
102
103    /**
104     * Writes audio data to the mixer via this source data line.  The requested
105     * number of bytes of data are read from the specified array,
106     * starting at the given offset into the array, and written to the data
107     * line's buffer.  If the caller attempts to write more data than can
108     * currently be written (see <code>DataLine#available available</code>),
109     * this method blocks until the requested amount of data has been written.
110     * This applies even if the requested amount of data to write is greater
111     * than the data line's buffer size.  However, if the data line is closed,
112     * stopped, or flushed before the requested amount has been written,
113     * the method no longer blocks, but returns the number of bytes
114     * written thus far.
115     * <p>
116     * The number of bytes that can be written without blocking can be ascertained
117     * using the <code>DataLine#available available</code> method of the
118     * <code>DataLine</code> interface.  (While it is guaranteed that
119     * this number of bytes can be written without blocking, there is no guarantee
120     * that attempts to write additional data will block.)
121     * <p>
122     * The number of bytes to write must represent an integral number of
123     * sample frames, such that:
124     * <br>
125     * <center><code>[ bytes written ] % [frame size in bytes ] == 0</code></center>
126     * <br>
127     * The return value will always meet this requirement.  A request to write a
128     * number of bytes representing a non-integral number of sample frames cannot
129     * be fulfilled and may result in an <code>IllegalArgumentException</code>.
130     *
131     * @param b a byte array containing data to be written to the data line
132     * @param off the offset from the beginning of the array, in bytes
133     * @param len the length, in bytes, of the valid data in the array
134     * (in other words, the requested amount of data to write, in bytes)
135     * @return the number of bytes actually written
136     * @throws IllegalArgumentException if the requested number of bytes does
137     * not represent an integral number of sample frames,
138     * or if <code>len</code> is negative
139     * @throws ArrayIndexOutOfBoundsException if <code>off</code> is negative,
140     * or <code>off+len</code> is greater than the length of the array
141     * <code>b</code>.
142     */
143    @Override
144    public int write(byte[] b, int off, int len) {
145        if (isMutable) {
146            return sourceDataLine.write(b, off, len);
147        } else {
148            if (isMutedFromSystem) {
149                byte[] newArr = new byte[b.length];
150                return sourceDataLine.write(newArr, off, len);
151            } else {
152                return sourceDataLine.write(b, off, len);
153            }
154        }
155    }
156}