Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/media/sound/AbstractMixer.java
38924 views
/*1* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.media.sound;2627import java.util.Vector;2829import javax.sound.sampled.Control;30import javax.sound.sampled.Mixer;31import javax.sound.sampled.Line;32import javax.sound.sampled.LineUnavailableException;3334/**35* Abstract Mixer. Implements Mixer (with abstract methods) and specifies36* some other common methods for use by our implementation.37*38* @author Kara Kytle39*/40//$$fb 2002-07-26: let AbstractMixer be an AbstractLine and NOT an AbstractDataLine!41abstract class AbstractMixer extends AbstractLine implements Mixer {4243// STATIC VARIABLES44protected static final int PCM = 0;45protected static final int ULAW = 1;46protected static final int ALAW = 2;474849// IMMUTABLE PROPERTIES5051/**52* Info object describing this mixer.53*/54private final Mixer.Info mixerInfo;5556/**57* source lines provided by this mixer58*/59protected Line.Info[] sourceLineInfo;6061/**62* target lines provided by this mixer63*/64protected Line.Info[] targetLineInfo;6566/**67* if any line of this mixer is started68*/69private boolean started = false;7071/**72* if this mixer had been opened manually with open()73* If it was, then it won't be closed automatically,74* only when close() is called manually.75*/76private boolean manuallyOpened = false;777879/**80* Supported formats for the mixer.81*/82//$$fb DELETE83//protected Vector formats = new Vector();848586// STATE VARIABLES878889/**90* Source lines (ports) currently open91*/92private final Vector sourceLines = new Vector();939495/**96* Target lines currently open.97*/98private final Vector targetLines = new Vector();99100101/**102* Constructs a new AbstractMixer.103* @param mixer the mixer with which this line is associated104* @param controls set of supported controls105*/106protected AbstractMixer(Mixer.Info mixerInfo,107Control[] controls,108Line.Info[] sourceLineInfo,109Line.Info[] targetLineInfo) {110111// Line.Info, AbstractMixer, Control[]112super(new Line.Info(Mixer.class), null, controls);113114// setup the line part115this.mixer = this;116if (controls == null) {117controls = new Control[0];118}119120// setup the mixer part121this.mixerInfo = mixerInfo;122this.sourceLineInfo = sourceLineInfo;123this.targetLineInfo = targetLineInfo;124}125126127// MIXER METHODS128129130public final Mixer.Info getMixerInfo() {131return mixerInfo;132}133134135public final Line.Info[] getSourceLineInfo() {136Line.Info[] localArray = new Line.Info[sourceLineInfo.length];137System.arraycopy(sourceLineInfo, 0, localArray, 0, sourceLineInfo.length);138return localArray;139}140141142public final Line.Info[] getTargetLineInfo() {143144Line.Info[] localArray = new Line.Info[targetLineInfo.length];145System.arraycopy(targetLineInfo, 0, localArray, 0, targetLineInfo.length);146return localArray;147}148149150public final Line.Info[] getSourceLineInfo(Line.Info info) {151152int i;153Vector vec = new Vector();154155for (i = 0; i < sourceLineInfo.length; i++) {156157if (info.matches(sourceLineInfo[i])) {158vec.addElement(sourceLineInfo[i]);159}160}161162Line.Info[] returnedArray = new Line.Info[vec.size()];163for (i = 0; i < returnedArray.length; i++) {164returnedArray[i] = (Line.Info)vec.elementAt(i);165}166167return returnedArray;168}169170171public final Line.Info[] getTargetLineInfo(Line.Info info) {172173int i;174Vector vec = new Vector();175176for (i = 0; i < targetLineInfo.length; i++) {177178if (info.matches(targetLineInfo[i])) {179vec.addElement(targetLineInfo[i]);180}181}182183Line.Info[] returnedArray = new Line.Info[vec.size()];184for (i = 0; i < returnedArray.length; i++) {185returnedArray[i] = (Line.Info)vec.elementAt(i);186}187188return returnedArray;189}190191192public final boolean isLineSupported(Line.Info info) {193194int i;195196for (i = 0; i < sourceLineInfo.length; i++) {197198if (info.matches(sourceLineInfo[i])) {199return true;200}201}202203for (i = 0; i < targetLineInfo.length; i++) {204205if (info.matches(targetLineInfo[i])) {206return true;207}208}209210return false;211}212213214public abstract Line getLine(Line.Info info) throws LineUnavailableException;215216public abstract int getMaxLines(Line.Info info);217218protected abstract void implOpen() throws LineUnavailableException;219protected abstract void implStart();220protected abstract void implStop();221protected abstract void implClose();222223224public final Line[] getSourceLines() {225226Line[] localLines;227228synchronized(sourceLines) {229230localLines = new Line[sourceLines.size()];231232for (int i = 0; i < localLines.length; i++) {233localLines[i] = (Line)sourceLines.elementAt(i);234}235}236237return localLines;238}239240241public final Line[] getTargetLines() {242243Line[] localLines;244245synchronized(targetLines) {246247localLines = new Line[targetLines.size()];248249for (int i = 0; i < localLines.length; i++) {250localLines[i] = (Line)targetLines.elementAt(i);251}252}253254return localLines;255}256257258/**259* Default implementation always throws an exception.260*/261public final void synchronize(Line[] lines, boolean maintainSync) {262throw new IllegalArgumentException("Synchronization not supported by this mixer.");263}264265266/**267* Default implementation always throws an exception.268*/269public final void unsynchronize(Line[] lines) {270throw new IllegalArgumentException("Synchronization not supported by this mixer.");271}272273274/**275* Default implementation always returns false.276*/277public final boolean isSynchronizationSupported(Line[] lines,278boolean maintainSync) {279return false;280}281282283// OVERRIDES OF ABSTRACT DATA LINE METHODS284285/**286* This implementation tries to open the mixer with its current format and buffer size settings.287*/288public final synchronized void open() throws LineUnavailableException {289open(true);290}291292/**293* This implementation tries to open the mixer with its current format and buffer size settings.294*/295final synchronized void open(boolean manual) throws LineUnavailableException {296if (Printer.trace) Printer.trace(">> AbstractMixer: open()");297if (!isOpen()) {298implOpen();299// if the mixer is not currently open, set open to true and send event300setOpen(true);301if (manual) {302manuallyOpened = true;303}304}305306if (Printer.trace) Printer.trace("<< AbstractMixer: open() succeeded");307}308309310// METHOD FOR INTERNAL IMPLEMENTATION USE311312313/**314* The default implementation of this method just determines whether315* this line is a source or target line, calls open(no-arg) on the316* mixer, and adds the line to the appropriate vector.317* The mixer may be opened at a format different than the line's318* format if it is a DataLine.319*/320final synchronized void open(Line line) throws LineUnavailableException {321322if (Printer.trace) Printer.trace(">> AbstractMixer: open(line = " + line + ")");323324// $$kk: 06.11.99: ignore ourselves for now325if (this.equals(line)) {326if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") nothing done");327return;328}329330// source line?331if (isSourceLine(line.getLineInfo())) {332if (! sourceLines.contains(line) ) {333// call the no-arg open method for the mixer; it should open at its334// default format if it is not open yet335open(false);336337// we opened successfully! add the line to the list338sourceLines.addElement(line);339}340} else {341// target line?342if(isTargetLine(line.getLineInfo())) {343if (! targetLines.contains(line) ) {344// call the no-arg open method for the mixer; it should open at its345// default format if it is not open yet346open(false);347348// we opened successfully! add the line to the list349targetLines.addElement(line);350}351} else {352if (Printer.err) Printer.err("Unknown line received for AbstractMixer.open(Line): " + line);353}354}355356if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") completed");357}358359360/**361* Removes this line from the list of open source lines and362* open target lines, if it exists in either.363* If the list is now empty, closes the mixer.364*/365final synchronized void close(Line line) {366367if (Printer.trace) Printer.trace(">> AbstractMixer: close(" + line + ")");368369// $$kk: 06.11.99: ignore ourselves for now370if (this.equals(line)) {371if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") nothing done");372return;373}374375sourceLines.removeElement(line);376targetLines.removeElement(line);377378if (Printer.debug) Printer.debug("AbstractMixer: close(line): sourceLines.size() now: " + sourceLines.size());379if (Printer.debug) Printer.debug("AbstractMixer: close(line): targetLines.size() now: " + targetLines.size());380381382if (sourceLines.isEmpty() && targetLines.isEmpty() && !manuallyOpened) {383if (Printer.trace) Printer.trace("AbstractMixer: close(" + line + "): need to close the mixer");384close();385}386387if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") succeeded");388}389390391/**392* Close all lines and then close this mixer.393*/394public final synchronized void close() {395if (Printer.trace) Printer.trace(">> AbstractMixer: close()");396if (isOpen()) {397// close all source lines398Line[] localLines = getSourceLines();399for (int i = 0; i<localLines.length; i++) {400localLines[i].close();401}402403// close all target lines404localLines = getTargetLines();405for (int i = 0; i<localLines.length; i++) {406localLines[i].close();407}408409implClose();410411// set the open state to false and send events412setOpen(false);413}414manuallyOpened = false;415if (Printer.trace) Printer.trace("<< AbstractMixer: close() succeeded");416}417418/**419* Starts the mixer.420*/421final synchronized void start(Line line) {422423if (Printer.trace) Printer.trace(">> AbstractMixer: start(" + line + ")");424425// $$kk: 06.11.99: ignore ourselves for now426if (this.equals(line)) {427if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") nothing done");428return;429}430431// we just start the mixer regardless of anything else here.432if (!started) {433if (Printer.debug) Printer.debug("AbstractMixer: start(line): starting the mixer");434implStart();435started = true;436}437438if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") succeeded");439}440441442/**443* Stops the mixer if this was the last running line.444*/445final synchronized void stop(Line line) {446447if (Printer.trace) Printer.trace(">> AbstractMixer: stop(" + line + ")");448449// $$kk: 06.11.99: ignore ourselves for now450if (this.equals(line)) {451if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") nothing done");452return;453}454455Vector localSourceLines = (Vector)sourceLines.clone();456for (int i = 0; i < localSourceLines.size(); i++) {457458// if any other open line is running, return459460// this covers clips and source data lines461if (localSourceLines.elementAt(i) instanceof AbstractDataLine) {462AbstractDataLine sourceLine = (AbstractDataLine)localSourceLines.elementAt(i);463if ( sourceLine.isStartedRunning() && (!sourceLine.equals(line)) ) {464if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running sourceLine: " + sourceLine);465return;466}467}468}469470Vector localTargetLines = (Vector)targetLines.clone();471for (int i = 0; i < localTargetLines.size(); i++) {472473// if any other open line is running, return474// this covers target data lines475if (localTargetLines.elementAt(i) instanceof AbstractDataLine) {476AbstractDataLine targetLine = (AbstractDataLine)localTargetLines.elementAt(i);477if ( targetLine.isStartedRunning() && (!targetLine.equals(line)) ) {478if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running targetLine: " + targetLine);479return;480}481}482}483484// otherwise, stop485if (Printer.debug) Printer.debug("AbstractMixer: stop(line): stopping the mixer");486started = false;487implStop();488489if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") succeeded");490}491492493494/**495* Determines whether this is a source line for this mixer.496* Right now this just checks whether it's supported, but should497* check whether it actually belongs to this mixer....498*/499final boolean isSourceLine(Line.Info info) {500501for (int i = 0; i < sourceLineInfo.length; i++) {502if (info.matches(sourceLineInfo[i])) {503return true;504}505}506507return false;508}509510511/**512* Determines whether this is a target line for this mixer.513* Right now this just checks whether it's supported, but should514* check whether it actually belongs to this mixer....515*/516final boolean isTargetLine(Line.Info info) {517518for (int i = 0; i < targetLineInfo.length; i++) {519if (info.matches(targetLineInfo[i])) {520return true;521}522}523524return false;525}526527528/**529* Returns the first complete Line.Info object it finds that530* matches the one specified, or null if no matching Line.Info531* object is found.532*/533final Line.Info getLineInfo(Line.Info info) {534if (info == null) {535return null;536}537// $$kk: 05.31.99: need to change this so that538// the format and buffer size get set in the539// returned info object for data lines??540for (int i = 0; i < sourceLineInfo.length; i++) {541if (info.matches(sourceLineInfo[i])) {542return sourceLineInfo[i];543}544}545546for (int i = 0; i < targetLineInfo.length; i++) {547if (info.matches(targetLineInfo[i])) {548return targetLineInfo[i];549}550}551552return null;553}554555}556557558