|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.media.sound; |
|
|
|
import java.util.Vector; |
|
|
|
import javax.sound.sampled.Control; |
|
import javax.sound.sampled.Mixer; |
|
import javax.sound.sampled.Line; |
|
import javax.sound.sampled.LineUnavailableException; |
|
|
|
/** |
|
* Abstract Mixer. Implements Mixer (with abstract methods) and specifies |
|
* some other common methods for use by our implementation. |
|
* |
|
* @author Kara Kytle |
|
*/ |
|
|
|
abstract class AbstractMixer extends AbstractLine implements Mixer { |
|
|
|
|
|
protected static final int PCM = 0; |
|
protected static final int ULAW = 1; |
|
protected static final int ALAW = 2; |
|
|
|
|
|
// IMMUTABLE PROPERTIES |
|
|
|
|
|
|
|
*/ |
|
private final Mixer.Info mixerInfo; |
|
|
|
|
|
|
|
*/ |
|
protected Line.Info[] sourceLineInfo; |
|
|
|
|
|
|
|
*/ |
|
protected Line.Info[] targetLineInfo; |
|
|
|
|
|
|
|
*/ |
|
private boolean started = false; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean manuallyOpened = false; |
|
|
|
|
|
/** |
|
* Supported formats for the mixer. |
|
*/ |
|
//$$fb DELETE |
|
//protected Vector formats = new Vector(); |
|
|
|
|
|
// STATE VARIABLES |
|
|
|
|
|
|
|
|
|
*/ |
|
private final Vector sourceLines = new Vector(); |
|
|
|
|
|
|
|
|
|
*/ |
|
private final Vector targetLines = new Vector(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected AbstractMixer(Mixer.Info mixerInfo, |
|
Control[] controls, |
|
Line.Info[] sourceLineInfo, |
|
Line.Info[] targetLineInfo) { |
|
|
|
|
|
super(new Line.Info(Mixer.class), null, controls); |
|
|
|
|
|
this.mixer = this; |
|
if (controls == null) { |
|
controls = new Control[0]; |
|
} |
|
|
|
|
|
this.mixerInfo = mixerInfo; |
|
this.sourceLineInfo = sourceLineInfo; |
|
this.targetLineInfo = targetLineInfo; |
|
} |
|
|
|
|
|
// MIXER METHODS |
|
|
|
|
|
public final Mixer.Info getMixerInfo() { |
|
return mixerInfo; |
|
} |
|
|
|
|
|
public final Line.Info[] getSourceLineInfo() { |
|
Line.Info[] localArray = new Line.Info[sourceLineInfo.length]; |
|
System.arraycopy(sourceLineInfo, 0, localArray, 0, sourceLineInfo.length); |
|
return localArray; |
|
} |
|
|
|
|
|
public final Line.Info[] getTargetLineInfo() { |
|
|
|
Line.Info[] localArray = new Line.Info[targetLineInfo.length]; |
|
System.arraycopy(targetLineInfo, 0, localArray, 0, targetLineInfo.length); |
|
return localArray; |
|
} |
|
|
|
|
|
public final Line.Info[] getSourceLineInfo(Line.Info info) { |
|
|
|
int i; |
|
Vector vec = new Vector(); |
|
|
|
for (i = 0; i < sourceLineInfo.length; i++) { |
|
|
|
if (info.matches(sourceLineInfo[i])) { |
|
vec.addElement(sourceLineInfo[i]); |
|
} |
|
} |
|
|
|
Line.Info[] returnedArray = new Line.Info[vec.size()]; |
|
for (i = 0; i < returnedArray.length; i++) { |
|
returnedArray[i] = (Line.Info)vec.elementAt(i); |
|
} |
|
|
|
return returnedArray; |
|
} |
|
|
|
|
|
public final Line.Info[] getTargetLineInfo(Line.Info info) { |
|
|
|
int i; |
|
Vector vec = new Vector(); |
|
|
|
for (i = 0; i < targetLineInfo.length; i++) { |
|
|
|
if (info.matches(targetLineInfo[i])) { |
|
vec.addElement(targetLineInfo[i]); |
|
} |
|
} |
|
|
|
Line.Info[] returnedArray = new Line.Info[vec.size()]; |
|
for (i = 0; i < returnedArray.length; i++) { |
|
returnedArray[i] = (Line.Info)vec.elementAt(i); |
|
} |
|
|
|
return returnedArray; |
|
} |
|
|
|
|
|
public final boolean isLineSupported(Line.Info info) { |
|
|
|
int i; |
|
|
|
for (i = 0; i < sourceLineInfo.length; i++) { |
|
|
|
if (info.matches(sourceLineInfo[i])) { |
|
return true; |
|
} |
|
} |
|
|
|
for (i = 0; i < targetLineInfo.length; i++) { |
|
|
|
if (info.matches(targetLineInfo[i])) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
public abstract Line getLine(Line.Info info) throws LineUnavailableException; |
|
|
|
public abstract int getMaxLines(Line.Info info); |
|
|
|
protected abstract void implOpen() throws LineUnavailableException; |
|
protected abstract void implStart(); |
|
protected abstract void implStop(); |
|
protected abstract void implClose(); |
|
|
|
|
|
public final Line[] getSourceLines() { |
|
|
|
Line[] localLines; |
|
|
|
synchronized(sourceLines) { |
|
|
|
localLines = new Line[sourceLines.size()]; |
|
|
|
for (int i = 0; i < localLines.length; i++) { |
|
localLines[i] = (Line)sourceLines.elementAt(i); |
|
} |
|
} |
|
|
|
return localLines; |
|
} |
|
|
|
|
|
public final Line[] getTargetLines() { |
|
|
|
Line[] localLines; |
|
|
|
synchronized(targetLines) { |
|
|
|
localLines = new Line[targetLines.size()]; |
|
|
|
for (int i = 0; i < localLines.length; i++) { |
|
localLines[i] = (Line)targetLines.elementAt(i); |
|
} |
|
} |
|
|
|
return localLines; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final void synchronize(Line[] lines, boolean maintainSync) { |
|
throw new IllegalArgumentException("Synchronization not supported by this mixer."); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final void unsynchronize(Line[] lines) { |
|
throw new IllegalArgumentException("Synchronization not supported by this mixer."); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final boolean isSynchronizationSupported(Line[] lines, |
|
boolean maintainSync) { |
|
return false; |
|
} |
|
|
|
|
|
// OVERRIDES OF ABSTRACT DATA LINE METHODS |
|
|
|
|
|
|
|
*/ |
|
public final synchronized void open() throws LineUnavailableException { |
|
open(true); |
|
} |
|
|
|
|
|
|
|
*/ |
|
final synchronized void open(boolean manual) throws LineUnavailableException { |
|
if (Printer.trace) Printer.trace(">> AbstractMixer: open()"); |
|
if (!isOpen()) { |
|
implOpen(); |
|
|
|
setOpen(true); |
|
if (manual) { |
|
manuallyOpened = true; |
|
} |
|
} |
|
|
|
if (Printer.trace) Printer.trace("<< AbstractMixer: open() succeeded"); |
|
} |
|
|
|
|
|
// METHOD FOR INTERNAL IMPLEMENTATION USE |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final synchronized void open(Line line) throws LineUnavailableException { |
|
|
|
if (Printer.trace) Printer.trace(">> AbstractMixer: open(line = " + line + ")"); |
|
|
|
|
|
if (this.equals(line)) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") nothing done"); |
|
return; |
|
} |
|
|
|
|
|
if (isSourceLine(line.getLineInfo())) { |
|
if (! sourceLines.contains(line) ) { |
|
// call the no-arg open method for the mixer; it should open at its |
|
|
|
open(false); |
|
|
|
|
|
sourceLines.addElement(line); |
|
} |
|
} else { |
|
|
|
if(isTargetLine(line.getLineInfo())) { |
|
if (! targetLines.contains(line) ) { |
|
// call the no-arg open method for the mixer; it should open at its |
|
|
|
open(false); |
|
|
|
|
|
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 + ") completed"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final synchronized void close(Line line) { |
|
|
|
if (Printer.trace) Printer.trace(">> AbstractMixer: close(" + line + ")"); |
|
|
|
|
|
if (this.equals(line)) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") nothing done"); |
|
return; |
|
} |
|
|
|
sourceLines.removeElement(line); |
|
targetLines.removeElement(line); |
|
|
|
if (Printer.debug) Printer.debug("AbstractMixer: close(line): sourceLines.size() now: " + sourceLines.size()); |
|
if (Printer.debug) Printer.debug("AbstractMixer: close(line): targetLines.size() now: " + targetLines.size()); |
|
|
|
|
|
if (sourceLines.isEmpty() && targetLines.isEmpty() && !manuallyOpened) { |
|
if (Printer.trace) Printer.trace("AbstractMixer: close(" + line + "): need to close the mixer"); |
|
close(); |
|
} |
|
|
|
if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") succeeded"); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final synchronized void close() { |
|
if (Printer.trace) Printer.trace(">> AbstractMixer: close()"); |
|
if (isOpen()) { |
|
|
|
Line[] localLines = getSourceLines(); |
|
for (int i = 0; i<localLines.length; i++) { |
|
localLines[i].close(); |
|
} |
|
|
|
|
|
localLines = getTargetLines(); |
|
for (int i = 0; i<localLines.length; i++) { |
|
localLines[i].close(); |
|
} |
|
|
|
implClose(); |
|
|
|
|
|
setOpen(false); |
|
} |
|
manuallyOpened = false; |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: close() succeeded"); |
|
} |
|
|
|
|
|
|
|
*/ |
|
final synchronized void start(Line line) { |
|
|
|
if (Printer.trace) Printer.trace(">> AbstractMixer: start(" + line + ")"); |
|
|
|
|
|
if (this.equals(line)) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") nothing done"); |
|
return; |
|
} |
|
|
|
|
|
if (!started) { |
|
if (Printer.debug) Printer.debug("AbstractMixer: start(line): starting the mixer"); |
|
implStart(); |
|
started = true; |
|
} |
|
|
|
if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") succeeded"); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
final synchronized void stop(Line line) { |
|
|
|
if (Printer.trace) Printer.trace(">> AbstractMixer: stop(" + line + ")"); |
|
|
|
|
|
if (this.equals(line)) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") nothing done"); |
|
return; |
|
} |
|
|
|
Vector localSourceLines = (Vector)sourceLines.clone(); |
|
for (int i = 0; i < localSourceLines.size(); i++) { |
|
|
|
// if any other open line is running, return |
|
|
|
|
|
if (localSourceLines.elementAt(i) instanceof AbstractDataLine) { |
|
AbstractDataLine sourceLine = (AbstractDataLine)localSourceLines.elementAt(i); |
|
if ( sourceLine.isStartedRunning() && (!sourceLine.equals(line)) ) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running sourceLine: " + sourceLine); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
Vector localTargetLines = (Vector)targetLines.clone(); |
|
for (int i = 0; i < localTargetLines.size(); i++) { |
|
|
|
// if any other open line is running, return |
|
|
|
if (localTargetLines.elementAt(i) instanceof AbstractDataLine) { |
|
AbstractDataLine targetLine = (AbstractDataLine)localTargetLines.elementAt(i); |
|
if ( targetLine.isStartedRunning() && (!targetLine.equals(line)) ) { |
|
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running targetLine: " + targetLine); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
if (Printer.debug) Printer.debug("AbstractMixer: stop(line): stopping the mixer"); |
|
started = false; |
|
implStop(); |
|
|
|
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") succeeded"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final boolean isSourceLine(Line.Info info) { |
|
|
|
for (int i = 0; i < sourceLineInfo.length; i++) { |
|
if (info.matches(sourceLineInfo[i])) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final boolean isTargetLine(Line.Info info) { |
|
|
|
for (int i = 0; i < targetLineInfo.length; i++) { |
|
if (info.matches(targetLineInfo[i])) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final Line.Info getLineInfo(Line.Info info) { |
|
if (info == null) { |
|
return null; |
|
} |
|
// $$kk: 05.31.99: need to change this so that |
|
// the format and buffer size get set in the |
|
|
|
for (int i = 0; i < sourceLineInfo.length; i++) { |
|
if (info.matches(sourceLineInfo[i])) { |
|
return sourceLineInfo[i]; |
|
} |
|
} |
|
|
|
for (int i = 0; i < targetLineInfo.length; i++) { |
|
if (info.matches(targetLineInfo[i])) { |
|
return targetLineInfo[i]; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
} |