Path: blob/master/src/java.desktop/share/classes/com/sun/media/sound/AbstractLine.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.Map;28import java.util.Vector;29import java.util.WeakHashMap;3031import javax.sound.sampled.AudioSystem;32import javax.sound.sampled.Control;33import javax.sound.sampled.Line;34import javax.sound.sampled.LineEvent;35import javax.sound.sampled.LineListener;36import javax.sound.sampled.LineUnavailableException;3738/**39* AbstractLine40*41* @author Kara Kytle42*/43abstract class AbstractLine implements Line {4445protected final Line.Info info;46protected Control[] controls;47AbstractMixer mixer;48private volatile boolean open;49private final Vector<Object> listeners = new Vector<>();5051/**52* Contains event dispatcher per thread group.53*/54private static final Map<ThreadGroup, EventDispatcher> dispatchers =55new WeakHashMap<>();5657/**58* Constructs a new AbstractLine.59* @param mixer the mixer with which this line is associated60* @param controls set of supported controls61*/62protected AbstractLine(Line.Info info, AbstractMixer mixer, Control[] controls) {6364if (controls == null) {65controls = new Control[0];66}6768this.info = info;69this.mixer = mixer;70this.controls = controls;71}7273// LINE METHODS7475@Override76public final Line.Info getLineInfo() {77return info;78}7980@Override81public final boolean isOpen() {82return open;83}8485@Override86public final void addLineListener(LineListener listener) {87synchronized(listeners) {88if ( ! (listeners.contains(listener)) ) {89listeners.addElement(listener);90}91}92}9394/**95* Removes an audio listener.96* @param listener listener to remove97*/98@Override99public final void removeLineListener(LineListener listener) {100listeners.removeElement(listener);101}102103/**104* Obtains the set of controls supported by the105* line. If no controls are supported, returns an106* array of length 0.107* @return control set108*/109@Override110public final Control[] getControls() {111Control[] returnedArray = new Control[controls.length];112113for (int i = 0; i < controls.length; i++) {114returnedArray[i] = controls[i];115}116117return returnedArray;118}119120@Override121public final boolean isControlSupported(Control.Type controlType) {122// protect against a NullPointerException123if (controlType == null) {124return false;125}126127for (int i = 0; i < controls.length; i++) {128if (controlType == controls[i].getType()) {129return true;130}131}132133return false;134}135136@Override137public final Control getControl(Control.Type controlType) {138// protect against a NullPointerException139if (controlType != null) {140141for (int i = 0; i < controls.length; i++) {142if (controlType == controls[i].getType()) {143return controls[i];144}145}146}147148throw new IllegalArgumentException("Unsupported control type: " + controlType);149}150151// HELPER METHODS152153/**154* This method sets the open state and generates155* events if it changes.156*/157final void setOpen(boolean open) {158boolean sendEvents = false;159long position = getLongFramePosition();160161synchronized (this) {162if (this.open != open) {163this.open = open;164sendEvents = true;165}166}167168if (sendEvents) {169if (open) {170sendEvents(new LineEvent(this, LineEvent.Type.OPEN, position));171} else {172sendEvents(new LineEvent(this, LineEvent.Type.CLOSE, position));173}174}175}176177/**178* Send line events.179*/180final void sendEvents(LineEvent event) {181getEventDispatcher().sendAudioEvents(event, listeners);182}183184/**185* This is an error in the API: getFramePosition186* should return a long value. At CD quality,187* the int value wraps around after 13 hours.188*/189public final int getFramePosition() {190return (int) getLongFramePosition();191}192193/**194* Return the frame position in a long value195* This implementation returns AudioSystem.NOT_SPECIFIED.196*/197public long getLongFramePosition() {198return AudioSystem.NOT_SPECIFIED;199}200201// $$kk: 06.03.99: returns the mixer used in construction.202// this is a hold-over from when there was a public method like203// this on line and should be fixed!!204final AbstractMixer getMixer() {205return mixer;206}207208final EventDispatcher getEventDispatcher() {209// create and start the global event thread210//TODO need a way to stop this thread when the engine is done211final ThreadGroup tg = Thread.currentThread().getThreadGroup();212synchronized (dispatchers) {213EventDispatcher eventDispatcher = dispatchers.get(tg);214if (eventDispatcher == null) {215eventDispatcher = new EventDispatcher();216dispatchers.put(tg, eventDispatcher);217eventDispatcher.start();218}219return eventDispatcher;220}221}222223@Override224public abstract void open() throws LineUnavailableException;225@Override226public abstract void close();227}228229230