25 |
25 |
26 package com.sun.media.sound; |
26 package com.sun.media.sound; |
27 |
27 |
28 import java.util.Vector; |
28 import java.util.Vector; |
29 |
29 |
|
30 import javax.sound.sampled.BooleanControl; |
|
31 import javax.sound.sampled.CompoundControl; |
30 import javax.sound.sampled.Control; |
32 import javax.sound.sampled.Control; |
|
33 import javax.sound.sampled.FloatControl; |
31 import javax.sound.sampled.Line; |
34 import javax.sound.sampled.Line; |
32 import javax.sound.sampled.LineUnavailableException; |
35 import javax.sound.sampled.LineUnavailableException; |
33 import javax.sound.sampled.Port; |
36 import javax.sound.sampled.Port; |
34 import javax.sound.sampled.BooleanControl; |
|
35 import javax.sound.sampled.CompoundControl; |
|
36 import javax.sound.sampled.FloatControl; |
|
37 |
|
38 |
37 |
39 /** |
38 /** |
40 * A Mixer which only provides Ports. |
39 * A Mixer which only provides Ports. |
41 * |
40 * |
42 * @author Florian Bomers |
41 * @author Florian Bomers |
43 */ |
42 */ |
44 final class PortMixer extends AbstractMixer { |
43 final class PortMixer extends AbstractMixer { |
45 |
44 |
46 // CONSTANTS |
|
47 private static final int SRC_UNKNOWN = 0x01; |
45 private static final int SRC_UNKNOWN = 0x01; |
48 private static final int SRC_MICROPHONE = 0x02; |
46 private static final int SRC_MICROPHONE = 0x02; |
49 private static final int SRC_LINE_IN = 0x03; |
47 private static final int SRC_LINE_IN = 0x03; |
50 private static final int SRC_COMPACT_DISC = 0x04; |
48 private static final int SRC_COMPACT_DISC = 0x04; |
51 private static final int SRC_MASK = 0xFF; |
49 private static final int SRC_MASK = 0xFF; |
54 private static final int DST_SPEAKER = 0x0200; |
52 private static final int DST_SPEAKER = 0x0200; |
55 private static final int DST_HEADPHONE = 0x0300; |
53 private static final int DST_HEADPHONE = 0x0300; |
56 private static final int DST_LINE_OUT = 0x0400; |
54 private static final int DST_LINE_OUT = 0x0400; |
57 private static final int DST_MASK = 0xFF00; |
55 private static final int DST_MASK = 0xFF00; |
58 |
56 |
59 // INSTANCE VARIABLES |
57 private final Port.Info[] portInfos; |
60 private Port.Info[] portInfos; |
|
61 // cache of instantiated ports |
58 // cache of instantiated ports |
62 private PortMixerPort[] ports; |
59 private PortMixerPort[] ports; |
63 |
60 |
64 // instance ID of the native implementation |
61 // instance ID of the native implementation |
65 private long id = 0; |
62 private long id = 0; |
66 |
63 |
67 // CONSTRUCTOR |
|
68 PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) { |
64 PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) { |
69 // pass in Line.Info, mixer, controls |
65 // pass in Line.Info, mixer, controls |
70 super(portMixerInfo, // Mixer.Info |
66 super(portMixerInfo, // Mixer.Info |
71 null, // Control[] |
67 null, // Control[] |
72 null, // Line.Info[] sourceLineInfo |
68 null, // Line.Info[] sourceLineInfo |
119 } |
115 } |
120 |
116 |
121 if (Printer.trace) Printer.trace("<< PortMixer: constructor completed"); |
117 if (Printer.trace) Printer.trace("<< PortMixer: constructor completed"); |
122 } |
118 } |
123 |
119 |
124 |
120 @Override |
125 // ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS |
|
126 |
|
127 public Line getLine(Line.Info info) throws LineUnavailableException { |
121 public Line getLine(Line.Info info) throws LineUnavailableException { |
128 Line.Info fullInfo = getLineInfo(info); |
122 Line.Info fullInfo = getLineInfo(info); |
129 |
123 |
130 if ((fullInfo != null) && (fullInfo instanceof Port.Info)) { |
124 if ((fullInfo != null) && (fullInfo instanceof Port.Info)) { |
131 for (int i = 0; i < portInfos.length; i++) { |
125 for (int i = 0; i < portInfos.length; i++) { |
151 return 1; |
145 return 1; |
152 } |
146 } |
153 return 0; |
147 return 0; |
154 } |
148 } |
155 |
149 |
156 |
150 @Override |
157 protected void implOpen() throws LineUnavailableException { |
151 protected void implOpen() throws LineUnavailableException { |
158 if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")"); |
152 if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")"); |
159 |
153 |
160 // open the mixer device |
154 // open the mixer device |
161 id = nOpen(getMixerIndex()); |
155 id = nOpen(getMixerIndex()); |
162 |
156 |
163 if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded."); |
157 if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded."); |
164 } |
158 } |
165 |
159 |
|
160 @Override |
166 protected void implClose() { |
161 protected void implClose() { |
167 if (Printer.trace) Printer.trace(">> PortMixer: implClose"); |
162 if (Printer.trace) Printer.trace(">> PortMixer: implClose"); |
168 |
163 |
169 // close the mixer device |
164 // close the mixer device |
170 long thisID = id; |
165 long thisID = id; |
179 } |
174 } |
180 |
175 |
181 if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded"); |
176 if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded"); |
182 } |
177 } |
183 |
178 |
|
179 @Override |
184 protected void implStart() {} |
180 protected void implStart() {} |
|
181 @Override |
185 protected void implStop() {} |
182 protected void implStop() {} |
186 |
|
187 // IMPLEMENTATION HELPERS |
|
188 |
183 |
189 private Port.Info getPortInfo(int portIndex, int type) { |
184 private Port.Info getPortInfo(int portIndex, int type) { |
190 switch (type) { |
185 switch (type) { |
191 case SRC_UNKNOWN: return new PortInfo(nGetPortName(getID(), portIndex), true); |
186 case SRC_UNKNOWN: return new PortInfo(nGetPortName(getID(), portIndex), true); |
192 case SRC_MICROPHONE: return Port.Info.MICROPHONE; |
187 case SRC_MICROPHONE: return Port.Info.MICROPHONE; |
221 |
216 |
222 long getID() { |
217 long getID() { |
223 return id; |
218 return id; |
224 } |
219 } |
225 |
220 |
226 // INNER CLASSES |
|
227 |
|
228 /** |
221 /** |
229 * Private inner class representing a Port for the PortMixer. |
222 * Private inner class representing a Port for the PortMixer. |
230 */ |
223 */ |
231 private static final class PortMixerPort extends AbstractLine |
224 private static final class PortMixerPort extends AbstractLine |
232 implements Port { |
225 implements Port { |
233 |
226 |
234 private final int portIndex; |
227 private final int portIndex; |
235 private long id; |
228 private long id; |
236 |
229 |
237 // CONSTRUCTOR |
|
238 private PortMixerPort(Port.Info info, |
230 private PortMixerPort(Port.Info info, |
239 PortMixer mixer, |
231 PortMixer mixer, |
240 int portIndex) { |
232 int portIndex) { |
241 super(info, mixer, null); |
233 super(info, mixer, null); |
242 if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info); |
234 if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info); |
243 this.portIndex = portIndex; |
235 this.portIndex = portIndex; |
244 } |
236 } |
245 |
|
246 |
|
247 // ABSTRACT METHOD IMPLEMENTATIONS |
|
248 |
|
249 // ABSTRACT LINE |
|
250 |
237 |
251 void implOpen() throws LineUnavailableException { |
238 void implOpen() throws LineUnavailableException { |
252 if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen()."); |
239 if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen()."); |
253 long newID = ((PortMixer) mixer).getID(); |
240 long newID = ((PortMixer) mixer).getID(); |
254 if ((id == 0) || (newID != id) || (controls.length == 0)) { |
241 if ((id == 0) || (newID != id) || (controls.length == 0)) { |
284 private void disposeControls() { |
271 private void disposeControls() { |
285 enableControls(controls, false); |
272 enableControls(controls, false); |
286 controls = new Control[0]; |
273 controls = new Control[0]; |
287 } |
274 } |
288 |
275 |
289 |
|
290 void implClose() { |
276 void implClose() { |
291 if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()"); |
277 if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()"); |
292 // get rid of controls |
278 // get rid of controls |
293 enableControls(controls, false); |
279 enableControls(controls, false); |
294 if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded"); |
280 if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded"); |
295 } |
281 } |
296 |
282 |
297 // METHOD OVERRIDES |
|
298 |
|
299 // this is very similar to open(AudioFormat, int) in AbstractDataLine... |
283 // this is very similar to open(AudioFormat, int) in AbstractDataLine... |
|
284 @Override |
300 public void open() throws LineUnavailableException { |
285 public void open() throws LineUnavailableException { |
301 synchronized (mixer) { |
286 synchronized (mixer) { |
302 // if the line is not currently open, try to open it with this format and buffer size |
287 // if the line is not currently open, try to open it with this format and buffer size |
303 if (!isOpen()) { |
288 if (!isOpen()) { |
304 if (Printer.trace) Printer.trace("> PortMixerPort: open"); |
289 if (Printer.trace) Printer.trace("> PortMixerPort: open"); |
340 } |
326 } |
341 |
327 |
342 } // class PortMixerPort |
328 } // class PortMixerPort |
343 |
329 |
344 /** |
330 /** |
345 * Private inner class representing a BooleanControl for PortMixerPort |
331 * Private inner class representing a BooleanControl for PortMixerPort. |
346 */ |
332 */ |
347 private static final class BoolCtrl extends BooleanControl { |
333 private static final class BoolCtrl extends BooleanControl { |
348 // the handle to the native control function |
334 // the handle to the native control function |
349 private final long controlID; |
335 private final long controlID; |
350 private boolean closed = false; |
336 private boolean closed = false; |
358 //return BooleanControl.Type.SELECT; |
344 //return BooleanControl.Type.SELECT; |
359 } |
345 } |
360 return new BCT(name); |
346 return new BCT(name); |
361 } |
347 } |
362 |
348 |
363 |
|
364 private BoolCtrl(long controlID, String name) { |
349 private BoolCtrl(long controlID, String name) { |
365 this(controlID, createType(name)); |
350 this(controlID, createType(name)); |
366 } |
351 } |
367 |
352 |
368 private BoolCtrl(long controlID, BooleanControl.Type typ) { |
353 private BoolCtrl(long controlID, BooleanControl.Type typ) { |
369 super(typ, false); |
354 super(typ, false); |
370 this.controlID = controlID; |
355 this.controlID = controlID; |
371 } |
356 } |
372 |
357 |
|
358 @Override |
373 public void setValue(boolean value) { |
359 public void setValue(boolean value) { |
374 if (!closed) { |
360 if (!closed) { |
375 nControlSetIntValue(controlID, value?1:0); |
361 nControlSetIntValue(controlID, value?1:0); |
376 } |
362 } |
377 } |
363 } |
378 |
364 |
|
365 @Override |
379 public boolean getValue() { |
366 public boolean getValue() { |
380 if (!closed) { |
367 if (!closed) { |
381 // never use any cached values |
368 // never use any cached values |
382 return (nControlGetIntValue(controlID)!=0)?true:false; |
369 return (nControlGetIntValue(controlID)!=0)?true:false; |
383 } |
370 } |
384 // ?? |
371 // ?? |
385 return false; |
372 return false; |
386 } |
373 } |
387 |
374 |
388 /** |
375 /** |
389 * inner class for custom types |
376 * inner class for custom types. |
390 */ |
377 */ |
391 private static final class BCT extends BooleanControl.Type { |
378 private static final class BCT extends BooleanControl.Type { |
392 private BCT(String name) { |
379 private BCT(String name) { |
393 super(name); |
380 super(name); |
394 } |
381 } |
395 } |
382 } |
396 } |
383 } |
397 |
384 |
398 /** |
385 /** |
399 * Private inner class representing a CompoundControl for PortMixerPort |
386 * Private inner class representing a CompoundControl for PortMixerPort. |
400 */ |
387 */ |
401 private static final class CompCtrl extends CompoundControl { |
388 private static final class CompCtrl extends CompoundControl { |
402 private CompCtrl(String name, Control[] controls) { |
389 private CompCtrl(String name, Control[] controls) { |
403 super(new CCT(name), controls); |
390 super(new CCT(name), controls); |
404 } |
391 } |
405 |
392 |
406 /** |
393 /** |
407 * inner class for custom compound control types |
394 * inner class for custom compound control types. |
408 */ |
395 */ |
409 private static final class CCT extends CompoundControl.Type { |
396 private static final class CCT extends CompoundControl.Type { |
410 private CCT(String name) { |
397 private CCT(String name) { |
411 super(name); |
398 super(name); |
412 } |
399 } |
413 } |
400 } |
414 } |
401 } |
415 |
402 |
416 /** |
403 /** |
417 * Private inner class representing a BooleanControl for PortMixerPort |
404 * Private inner class representing a BooleanControl for PortMixerPort. |
418 */ |
405 */ |
419 private static final class FloatCtrl extends FloatControl { |
406 private static final class FloatCtrl extends FloatControl { |
420 // the handle to the native control function |
407 // the handle to the native control function |
421 private final long controlID; |
408 private final long controlID; |
422 private boolean closed = false; |
409 private boolean closed = false; |
444 float min, float max, float precision, String units) { |
431 float min, float max, float precision, String units) { |
445 super(typ, min, max, precision, 1000, min, units); |
432 super(typ, min, max, precision, 1000, min, units); |
446 this.controlID = controlID; |
433 this.controlID = controlID; |
447 } |
434 } |
448 |
435 |
|
436 @Override |
449 public void setValue(float value) { |
437 public void setValue(float value) { |
450 if (!closed) { |
438 if (!closed) { |
451 nControlSetFloatValue(controlID, value); |
439 nControlSetFloatValue(controlID, value); |
452 } |
440 } |
453 } |
441 } |
454 |
442 |
|
443 @Override |
455 public float getValue() { |
444 public float getValue() { |
456 if (!closed) { |
445 if (!closed) { |
457 // never use any cached values |
446 // never use any cached values |
458 return nControlGetFloatValue(controlID); |
447 return nControlGetFloatValue(controlID); |
459 } |
448 } |
460 // ?? |
449 // ?? |
461 return getMinimum(); |
450 return getMinimum(); |
462 } |
451 } |
463 |
452 |
464 /** |
453 /** |
465 * inner class for custom types |
454 * inner class for custom types. |
466 */ |
455 */ |
467 private static final class FCT extends FloatControl.Type { |
456 private static final class FCT extends FloatControl.Type { |
468 private FCT(String name) { |
457 private FCT(String name) { |
469 super(name); |
458 super(name); |
470 } |
459 } |
471 } |
460 } |
472 } |
461 } |
473 |
462 |
474 /** |
463 /** |
475 * Private inner class representing a port info |
464 * Private inner class representing a port info. |
476 */ |
465 */ |
477 private static final class PortInfo extends Port.Info { |
466 private static final class PortInfo extends Port.Info { |
478 private PortInfo(String name, boolean isSource) { |
467 private PortInfo(String name, boolean isSource) { |
479 super(Port.class, name, isSource); |
468 super(Port.class, name, isSource); |
480 } |
469 } |