Path: blob/master/src/java.desktop/share/classes/com/sun/media/sound/AbstractMixer.java
41161 views
/*1* Copyright (c) 1999, 2019, 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.Line;31import javax.sound.sampled.LineUnavailableException;32import javax.sound.sampled.Mixer;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;7778// STATE VARIABLES7980/**81* Source lines (ports) currently open.82*/83private final Vector<Line> sourceLines = new Vector<>();8485/**86* Target lines currently open.87*/88private final Vector<Line> targetLines = new Vector<>();8990/**91* Constructs a new AbstractMixer.92* @param mixerInfo the mixer with which this line is associated93* @param controls set of supported controls94*/95protected AbstractMixer(Mixer.Info mixerInfo,96Control[] controls,97Line.Info[] sourceLineInfo,98Line.Info[] targetLineInfo) {99100// Line.Info, AbstractMixer, Control[]101super(new Line.Info(Mixer.class), null, controls);102103// setup the line part104this.mixer = this;105if (controls == null) {106controls = new Control[0];107}108109// setup the mixer part110this.mixerInfo = mixerInfo;111this.sourceLineInfo = sourceLineInfo;112this.targetLineInfo = targetLineInfo;113}114115// MIXER METHODS116117@Override118public final Mixer.Info getMixerInfo() {119return mixerInfo;120}121122@Override123public final Line.Info[] getSourceLineInfo() {124Line.Info[] localArray = new Line.Info[sourceLineInfo.length];125System.arraycopy(sourceLineInfo, 0, localArray, 0, sourceLineInfo.length);126return localArray;127}128129@Override130public final Line.Info[] getTargetLineInfo() {131Line.Info[] localArray = new Line.Info[targetLineInfo.length];132System.arraycopy(targetLineInfo, 0, localArray, 0, targetLineInfo.length);133return localArray;134}135136@Override137public final Line.Info[] getSourceLineInfo(Line.Info info) {138139int i;140Vector<Line.Info> vec = new Vector<>();141142for (i = 0; i < sourceLineInfo.length; i++) {143144if (info.matches(sourceLineInfo[i])) {145vec.addElement(sourceLineInfo[i]);146}147}148149Line.Info[] returnedArray = new Line.Info[vec.size()];150for (i = 0; i < returnedArray.length; i++) {151returnedArray[i] = vec.elementAt(i);152}153154return returnedArray;155}156157@Override158public final Line.Info[] getTargetLineInfo(Line.Info info) {159160int i;161Vector<Line.Info> vec = new Vector<>();162163for (i = 0; i < targetLineInfo.length; i++) {164165if (info.matches(targetLineInfo[i])) {166vec.addElement(targetLineInfo[i]);167}168}169170Line.Info[] returnedArray = new Line.Info[vec.size()];171for (i = 0; i < returnedArray.length; i++) {172returnedArray[i] = vec.elementAt(i);173}174175return returnedArray;176}177178@Override179public final boolean isLineSupported(Line.Info info) {180181int i;182183for (i = 0; i < sourceLineInfo.length; i++) {184185if (info.matches(sourceLineInfo[i])) {186return true;187}188}189190for (i = 0; i < targetLineInfo.length; i++) {191192if (info.matches(targetLineInfo[i])) {193return true;194}195}196197return false;198}199200@Override201public abstract Line getLine(Line.Info info) throws LineUnavailableException;202203@Override204public abstract int getMaxLines(Line.Info info);205206protected abstract void implOpen() throws LineUnavailableException;207protected abstract void implStart();208protected abstract void implStop();209protected abstract void implClose();210211@Override212public final Line[] getSourceLines() {213214Line[] localLines;215216synchronized(sourceLines) {217218localLines = new Line[sourceLines.size()];219220for (int i = 0; i < localLines.length; i++) {221localLines[i] = sourceLines.elementAt(i);222}223}224225return localLines;226}227228@Override229public final Line[] getTargetLines() {230231Line[] localLines;232233synchronized(targetLines) {234235localLines = new Line[targetLines.size()];236237for (int i = 0; i < localLines.length; i++) {238localLines[i] = targetLines.elementAt(i);239}240}241242return localLines;243}244245/**246* Default implementation always throws an exception.247*/248@Override249public final void synchronize(Line[] lines, boolean maintainSync) {250throw new IllegalArgumentException("Synchronization not supported by this mixer.");251}252253/**254* Default implementation always throws an exception.255*/256@Override257public final void unsynchronize(Line[] lines) {258throw new IllegalArgumentException("Synchronization not supported by this mixer.");259}260261/**262* Default implementation always returns false.263*/264@Override265public final boolean isSynchronizationSupported(Line[] lines,266boolean maintainSync) {267return false;268}269270// OVERRIDES OF ABSTRACT DATA LINE METHODS271272/**273* This implementation tries to open the mixer with its current format and buffer size settings.274*/275@Override276public final synchronized void open() throws LineUnavailableException {277open(true);278}279280/**281* This implementation tries to open the mixer with its current format and buffer size settings.282*/283final synchronized void open(boolean manual) throws LineUnavailableException {284if (!isOpen()) {285implOpen();286// if the mixer is not currently open, set open to true and send event287setOpen(true);288if (manual) {289manuallyOpened = true;290}291}292}293294// METHOD FOR INTERNAL IMPLEMENTATION USE295296/**297* The default implementation of this method just determines whether298* this line is a source or target line, calls open(no-arg) on the299* mixer, and adds the line to the appropriate vector.300* The mixer may be opened at a format different than the line's301* format if it is a DataLine.302*/303final synchronized void open(Line line) throws LineUnavailableException {304// $$kk: 06.11.99: ignore ourselves for now305if (this.equals(line)) {306return;307}308309// source line?310if (isSourceLine(line.getLineInfo())) {311if (! sourceLines.contains(line) ) {312// call the no-arg open method for the mixer; it should open at its313// default format if it is not open yet314open(false);315316// we opened successfully! add the line to the list317sourceLines.addElement(line);318}319} else {320// target line?321if(isTargetLine(line.getLineInfo())) {322if (! targetLines.contains(line) ) {323// call the no-arg open method for the mixer; it should open at its324// default format if it is not open yet325open(false);326327// we opened successfully! add the line to the list328targetLines.addElement(line);329}330} else {331if (Printer.err) Printer.err("Unknown line received for AbstractMixer.open(Line): " + line);332}333}334}335336/**337* Removes this line from the list of open source lines and338* open target lines, if it exists in either.339* If the list is now empty, closes the mixer.340*/341final synchronized void close(Line line) {342// $$kk: 06.11.99: ignore ourselves for now343if (this.equals(line)) {344return;345}346347sourceLines.removeElement(line);348targetLines.removeElement(line);349350if (sourceLines.isEmpty() && targetLines.isEmpty() && !manuallyOpened) {351close();352}353}354355/**356* Close all lines and then close this mixer.357*/358@Override359public final synchronized void close() {360if (isOpen()) {361// close all source lines362Line[] localLines = getSourceLines();363for (int i = 0; i<localLines.length; i++) {364localLines[i].close();365}366367// close all target lines368localLines = getTargetLines();369for (int i = 0; i<localLines.length; i++) {370localLines[i].close();371}372373implClose();374375// set the open state to false and send events376setOpen(false);377}378manuallyOpened = false;379}380381/**382* Starts the mixer.383*/384final synchronized void start(Line line) {385// $$kk: 06.11.99: ignore ourselves for now386if (this.equals(line)) {387return;388}389390// we just start the mixer regardless of anything else here.391if (!started) {392implStart();393started = true;394}395}396397/**398* Stops the mixer if this was the last running line.399*/400final synchronized void stop(Line line) {401// $$kk: 06.11.99: ignore ourselves for now402if (this.equals(line)) {403return;404}405406@SuppressWarnings("unchecked")407Vector<Line> localSourceLines = (Vector<Line>)sourceLines.clone();408for (int i = 0; i < localSourceLines.size(); i++) {409410// if any other open line is running, return411412// this covers clips and source data lines413if (localSourceLines.elementAt(i) instanceof AbstractDataLine) {414AbstractDataLine sourceLine = (AbstractDataLine)localSourceLines.elementAt(i);415if ( sourceLine.isStartedRunning() && (!sourceLine.equals(line)) ) {416return;417}418}419}420421@SuppressWarnings("unchecked")422Vector<Line> localTargetLines = (Vector<Line>)targetLines.clone();423for (int i = 0; i < localTargetLines.size(); i++) {424425// if any other open line is running, return426// this covers target data lines427if (localTargetLines.elementAt(i) instanceof AbstractDataLine) {428AbstractDataLine targetLine = (AbstractDataLine)localTargetLines.elementAt(i);429if ( targetLine.isStartedRunning() && (!targetLine.equals(line)) ) {430return;431}432}433}434435// otherwise, stop436started = false;437implStop();438}439440/**441* Determines whether this is a source line for this mixer.442* Right now this just checks whether it's supported, but should443* check whether it actually belongs to this mixer....444*/445final boolean isSourceLine(Line.Info info) {446447for (int i = 0; i < sourceLineInfo.length; i++) {448if (info.matches(sourceLineInfo[i])) {449return true;450}451}452453return false;454}455456/**457* Determines whether this is a target line for this mixer.458* Right now this just checks whether it's supported, but should459* check whether it actually belongs to this mixer....460*/461final boolean isTargetLine(Line.Info info) {462463for (int i = 0; i < targetLineInfo.length; i++) {464if (info.matches(targetLineInfo[i])) {465return true;466}467}468469return false;470}471472/**473* Returns the first complete Line.Info object it finds that474* matches the one specified, or null if no matching Line.Info475* object is found.476*/477final Line.Info getLineInfo(Line.Info info) {478if (info == null) {479return null;480}481// $$kk: 05.31.99: need to change this so that482// the format and buffer size get set in the483// returned info object for data lines??484for (int i = 0; i < sourceLineInfo.length; i++) {485if (info.matches(sourceLineInfo[i])) {486return sourceLineInfo[i];487}488}489490for (int i = 0; i < targetLineInfo.length; i++) {491if (info.matches(targetLineInfo[i])) {492return targetLineInfo[i];493}494}495return null;496}497}498499500