19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.sound; 27 28 import java.util.Map; 29 import java.util.Vector; 30 import java.util.WeakHashMap; 31 32 import javax.sound.sampled.AudioSystem; 33 import javax.sound.sampled.Control; 34 import javax.sound.sampled.Line; 35 import javax.sound.sampled.LineEvent; 36 import javax.sound.sampled.LineListener; 37 import javax.sound.sampled.LineUnavailableException; 38 39 40 /** 41 * AbstractLine 42 * 43 * @author Kara Kytle 44 */ 45 abstract class AbstractLine implements Line { 46 47 protected final Line.Info info; 48 protected Control[] controls; 49 AbstractMixer mixer; 50 private volatile boolean open; 51 private final Vector<Object> listeners = new Vector<>(); 52 53 /** 54 * Contains event dispatcher per thread group. 55 */ 56 private static final Map<ThreadGroup, EventDispatcher> dispatchers = 57 new WeakHashMap<>(); 58 59 /** 60 * Constructs a new AbstractLine. 61 * @param mixer the mixer with which this line is associated 62 * @param controls set of supported controls 63 */ 64 protected AbstractLine(Line.Info info, AbstractMixer mixer, Control[] controls) { 65 66 if (controls == null) { 67 controls = new Control[0]; 68 } 69 70 this.info = info; 71 this.mixer = mixer; 72 this.controls = controls; 73 } 74 75 76 // LINE METHODS 77 78 public final Line.Info getLineInfo() { 79 return info; 80 } 81 82 83 public final boolean isOpen() { 84 return open; 85 } 86 87 88 public final void addLineListener(LineListener listener) { 89 synchronized(listeners) { 90 if ( ! (listeners.contains(listener)) ) { 91 listeners.addElement(listener); 92 } 93 } 94 } 95 96 97 /** 98 * Removes an audio listener. 99 * @param listener listener to remove 100 */ 101 public final void removeLineListener(LineListener listener) { 102 listeners.removeElement(listener); 103 } 104 105 106 /** 107 * Obtains the set of controls supported by the 108 * line. If no controls are supported, returns an 109 * array of length 0. 110 * @return control set 111 */ 112 public final Control[] getControls() { 113 Control[] returnedArray = new Control[controls.length]; 114 115 for (int i = 0; i < controls.length; i++) { 116 returnedArray[i] = controls[i]; 117 } 118 119 return returnedArray; 120 } 121 122 123 public final boolean isControlSupported(Control.Type controlType) { 124 // protect against a NullPointerException 125 if (controlType == null) { 126 return false; 127 } 128 129 for (int i = 0; i < controls.length; i++) { 130 if (controlType == controls[i].getType()) { 131 return true; 132 } 133 } 134 135 return false; 136 } 137 138 139 public final Control getControl(Control.Type controlType) { 140 // protect against a NullPointerException 141 if (controlType != null) { 142 143 for (int i = 0; i < controls.length; i++) { 144 if (controlType == controls[i].getType()) { 145 return controls[i]; 146 } 147 } 148 } 149 150 throw new IllegalArgumentException("Unsupported control type: " + controlType); 151 } 152 153 154 // HELPER METHODS 155 156 157 /** 158 * This method sets the open state and generates 159 * events if it changes. 160 */ 161 final void setOpen(boolean open) { 162 163 if (Printer.trace) Printer.trace("> "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open); 164 165 boolean sendEvents = false; 166 long position = getLongFramePosition(); 167 168 synchronized (this) { 169 if (this.open != open) { 170 this.open = open; 171 sendEvents = true; 172 } 173 } 174 175 if (sendEvents) { 176 if (open) { 177 sendEvents(new LineEvent(this, LineEvent.Type.OPEN, position)); 178 } else { 179 sendEvents(new LineEvent(this, LineEvent.Type.CLOSE, position)); 180 } 181 } 182 if (Printer.trace) Printer.trace("< "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open); 183 } 184 185 186 /** 187 * Send line events. 188 */ 189 final void sendEvents(LineEvent event) { 190 getEventDispatcher().sendAudioEvents(event, listeners); 191 } 192 193 194 /** 195 * This is an error in the API: getFramePosition 196 * should return a long value. At CD quality, 197 * the int value wraps around after 13 hours. 198 */ 199 public final int getFramePosition() { 200 return (int) getLongFramePosition(); 201 } 202 203 204 /** 205 * Return the frame position in a long value 206 * This implementation returns AudioSystem.NOT_SPECIFIED. 207 */ 208 public long getLongFramePosition() { 209 return AudioSystem.NOT_SPECIFIED; 210 } 211 212 213 // $$kk: 06.03.99: returns the mixer used in construction. 214 // this is a hold-over from when there was a public method like 215 // this on line and should be fixed!! 216 final AbstractMixer getMixer() { 217 return mixer; 218 } 219 220 final EventDispatcher getEventDispatcher() { 221 // create and start the global event thread 222 //TODO need a way to stop this thread when the engine is done 223 final ThreadGroup tg = Thread.currentThread().getThreadGroup(); 224 synchronized (dispatchers) { 225 EventDispatcher eventDispatcher = dispatchers.get(tg); 226 if (eventDispatcher == null) { 227 eventDispatcher = new EventDispatcher(); 228 dispatchers.put(tg, eventDispatcher); 229 eventDispatcher.start(); 230 } 231 return eventDispatcher; 232 } 233 } 234 235 // ABSTRACT METHODS 236 237 public abstract void open() throws LineUnavailableException; 238 public abstract void close(); 239 } | 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.sound; 27 28 import java.util.Map; 29 import java.util.Vector; 30 import java.util.WeakHashMap; 31 32 import javax.sound.sampled.AudioSystem; 33 import javax.sound.sampled.Control; 34 import javax.sound.sampled.Line; 35 import javax.sound.sampled.LineEvent; 36 import javax.sound.sampled.LineListener; 37 import javax.sound.sampled.LineUnavailableException; 38 39 /** 40 * AbstractLine 41 * 42 * @author Kara Kytle 43 */ 44 abstract class AbstractLine implements Line { 45 46 protected final Line.Info info; 47 protected Control[] controls; 48 AbstractMixer mixer; 49 private volatile boolean open; 50 private final Vector<Object> listeners = new Vector<>(); 51 52 /** 53 * Contains event dispatcher per thread group. 54 */ 55 private static final Map<ThreadGroup, EventDispatcher> dispatchers = 56 new WeakHashMap<>(); 57 58 /** 59 * Constructs a new AbstractLine. 60 * @param mixer the mixer with which this line is associated 61 * @param controls set of supported controls 62 */ 63 protected AbstractLine(Line.Info info, AbstractMixer mixer, Control[] controls) { 64 65 if (controls == null) { 66 controls = new Control[0]; 67 } 68 69 this.info = info; 70 this.mixer = mixer; 71 this.controls = controls; 72 } 73 74 // LINE METHODS 75 76 @Override 77 public final Line.Info getLineInfo() { 78 return info; 79 } 80 81 @Override 82 public final boolean isOpen() { 83 return open; 84 } 85 86 @Override 87 public final void addLineListener(LineListener listener) { 88 synchronized(listeners) { 89 if ( ! (listeners.contains(listener)) ) { 90 listeners.addElement(listener); 91 } 92 } 93 } 94 95 /** 96 * Removes an audio listener. 97 * @param listener listener to remove 98 */ 99 @Override 100 public final void removeLineListener(LineListener listener) { 101 listeners.removeElement(listener); 102 } 103 104 /** 105 * Obtains the set of controls supported by the 106 * line. If no controls are supported, returns an 107 * array of length 0. 108 * @return control set 109 */ 110 @Override 111 public final Control[] getControls() { 112 Control[] returnedArray = new Control[controls.length]; 113 114 for (int i = 0; i < controls.length; i++) { 115 returnedArray[i] = controls[i]; 116 } 117 118 return returnedArray; 119 } 120 121 @Override 122 public final boolean isControlSupported(Control.Type controlType) { 123 // protect against a NullPointerException 124 if (controlType == null) { 125 return false; 126 } 127 128 for (int i = 0; i < controls.length; i++) { 129 if (controlType == controls[i].getType()) { 130 return true; 131 } 132 } 133 134 return false; 135 } 136 137 @Override 138 public final Control getControl(Control.Type controlType) { 139 // protect against a NullPointerException 140 if (controlType != null) { 141 142 for (int i = 0; i < controls.length; i++) { 143 if (controlType == controls[i].getType()) { 144 return controls[i]; 145 } 146 } 147 } 148 149 throw new IllegalArgumentException("Unsupported control type: " + controlType); 150 } 151 152 // HELPER METHODS 153 154 /** 155 * This method sets the open state and generates 156 * events if it changes. 157 */ 158 final void setOpen(boolean open) { 159 160 if (Printer.trace) Printer.trace("> "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open); 161 162 boolean sendEvents = false; 163 long position = getLongFramePosition(); 164 165 synchronized (this) { 166 if (this.open != open) { 167 this.open = open; 168 sendEvents = true; 169 } 170 } 171 172 if (sendEvents) { 173 if (open) { 174 sendEvents(new LineEvent(this, LineEvent.Type.OPEN, position)); 175 } else { 176 sendEvents(new LineEvent(this, LineEvent.Type.CLOSE, position)); 177 } 178 } 179 if (Printer.trace) Printer.trace("< "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open); 180 } 181 182 /** 183 * Send line events. 184 */ 185 final void sendEvents(LineEvent event) { 186 getEventDispatcher().sendAudioEvents(event, listeners); 187 } 188 189 /** 190 * This is an error in the API: getFramePosition 191 * should return a long value. At CD quality, 192 * the int value wraps around after 13 hours. 193 */ 194 public final int getFramePosition() { 195 return (int) getLongFramePosition(); 196 } 197 198 /** 199 * Return the frame position in a long value 200 * This implementation returns AudioSystem.NOT_SPECIFIED. 201 */ 202 public long getLongFramePosition() { 203 return AudioSystem.NOT_SPECIFIED; 204 } 205 206 // $$kk: 06.03.99: returns the mixer used in construction. 207 // this is a hold-over from when there was a public method like 208 // this on line and should be fixed!! 209 final AbstractMixer getMixer() { 210 return mixer; 211 } 212 213 final EventDispatcher getEventDispatcher() { 214 // create and start the global event thread 215 //TODO need a way to stop this thread when the engine is done 216 final ThreadGroup tg = Thread.currentThread().getThreadGroup(); 217 synchronized (dispatchers) { 218 EventDispatcher eventDispatcher = dispatchers.get(tg); 219 if (eventDispatcher == null) { 220 eventDispatcher = new EventDispatcher(); 221 dispatchers.put(tg, eventDispatcher); 222 eventDispatcher.start(); 223 } 224 return eventDispatcher; 225 } 226 } 227 228 @Override 229 public abstract void open() throws LineUnavailableException; 230 @Override 231 public abstract void close(); 232 } |