Path: blob/master/src/java.desktop/share/classes/com/sun/media/sound/AbstractLine.java
66646 views
/*1* Copyright (c) 1999, 2021, 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();160161if (this.open != open) {162this.open = open;163sendEvents = true;164}165166if (sendEvents) {167if (open) {168sendEvents(new LineEvent(this, LineEvent.Type.OPEN, position));169} else {170sendEvents(new LineEvent(this, LineEvent.Type.CLOSE, position));171}172}173}174175/**176* Send line events.177*/178final void sendEvents(LineEvent event) {179getEventDispatcher().sendAudioEvents(event, listeners);180}181182/**183* This is an error in the API: getFramePosition184* should return a long value. At CD quality,185* the int value wraps around after 13 hours.186*/187public final int getFramePosition() {188return (int) getLongFramePosition();189}190191/**192* Return the frame position in a long value193* This implementation returns AudioSystem.NOT_SPECIFIED.194*/195public long getLongFramePosition() {196return AudioSystem.NOT_SPECIFIED;197}198199// $$kk: 06.03.99: returns the mixer used in construction.200// this is a hold-over from when there was a public method like201// this on line and should be fixed!!202final AbstractMixer getMixer() {203return mixer;204}205206final EventDispatcher getEventDispatcher() {207// create and start the global event thread208//TODO need a way to stop this thread when the engine is done209final ThreadGroup tg = Thread.currentThread().getThreadGroup();210synchronized (dispatchers) {211EventDispatcher eventDispatcher = dispatchers.get(tg);212if (eventDispatcher == null) {213eventDispatcher = new EventDispatcher();214dispatchers.put(tg, eventDispatcher);215eventDispatcher.start();216}217return eventDispatcher;218}219}220221@Override222public abstract void open() throws LineUnavailableException;223@Override224public abstract void close();225}226227228