Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java
41159 views
1
/*
2
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
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 javax.sound.sampled;
27
28
import java.io.File;
29
import java.io.IOException;
30
import java.io.InputStream;
31
import java.io.OutputStream;
32
import java.net.URL;
33
import java.util.ArrayList;
34
import java.util.Collections;
35
import java.util.HashSet;
36
import java.util.List;
37
import java.util.Objects;
38
import java.util.Properties;
39
import java.util.Set;
40
import java.util.Vector;
41
42
import javax.sound.sampled.spi.AudioFileReader;
43
import javax.sound.sampled.spi.AudioFileWriter;
44
import javax.sound.sampled.spi.FormatConversionProvider;
45
import javax.sound.sampled.spi.MixerProvider;
46
47
import com.sun.media.sound.JDK13Services;
48
49
/* $fb TODO:
50
* - consistent usage of (typed) collections
51
*/
52
53
54
/**
55
* The {@code AudioSystem} class acts as the entry point to the sampled-audio
56
* system resources. This class lets you query and access the mixers that are
57
* installed on the system. {@code AudioSystem} includes a number of methods for
58
* converting audio data between different formats, and for translating between
59
* audio files and streams. It also provides a method for obtaining a
60
* {@link Line} directly from the {@code AudioSystem} without dealing explicitly
61
* with mixers.
62
* <p>
63
* Properties can be used to specify the default mixer for specific line types.
64
* Both system properties and a properties file are considered. The
65
* "sound.properties" properties file is read from an implementation-specific
66
* location (typically it is the {@code conf} directory in the Java installation
67
* directory). The optional "javax.sound.config.file" system property can be
68
* used to specify the properties file that will be read as the initial
69
* configuration. If a property exists both as a system property and in the
70
* properties file, the system property takes precedence. If none is specified,
71
* a suitable default is chosen among the available devices. The syntax of the
72
* properties file is specified in
73
* {@link Properties#load(InputStream) Properties.load}. The following table
74
* lists the available property keys and which methods consider them:
75
*
76
* <table class="striped">
77
* <caption>Audio System Property Keys</caption>
78
* <thead>
79
* <tr>
80
* <th scope="col">Property Key
81
* <th scope="col">Interface
82
* <th scope="col">Affected Method(s)
83
* </thead>
84
* <tbody>
85
* <tr>
86
* <th scope="row">{@code javax.sound.sampled.Clip}
87
* <td>{@link Clip}
88
* <td>{@link #getLine}, {@link #getClip}
89
* <tr>
90
* <th scope="row">{@code javax.sound.sampled.Port}
91
* <td>{@link Port}
92
* <td>{@link #getLine}
93
* <tr>
94
* <th scope="row">{@code javax.sound.sampled.SourceDataLine}
95
* <td>{@link SourceDataLine}
96
* <td>{@link #getLine}, {@link #getSourceDataLine}
97
* <tr>
98
* <th scope="row">{@code javax.sound.sampled.TargetDataLine}
99
* <td>{@link TargetDataLine}
100
* <td>{@link #getLine}, {@link #getTargetDataLine}
101
* </tbody>
102
* </table>
103
*
104
* The property value consists of the provider class name and the mixer name,
105
* separated by the hash mark ("#"). The provider class name is the
106
* fully-qualified name of a concrete {@link MixerProvider mixer provider}
107
* class. The mixer name is matched against the {@code String} returned by the
108
* {@code getName} method of {@code Mixer.Info}. Either the class name, or the
109
* mixer name may be omitted. If only the class name is specified, the trailing
110
* hash mark is optional.
111
* <p>
112
* If the provider class is specified, and it can be successfully retrieved from
113
* the installed providers, the list of {@code Mixer.Info} objects is retrieved
114
* from the provider. Otherwise, or when these mixers do not provide a
115
* subsequent match, the list is retrieved from {@link #getMixerInfo} to contain
116
* all available {@code Mixer.Info} objects.
117
* <p>
118
* If a mixer name is specified, the resulting list of {@code Mixer.Info}
119
* objects is searched: the first one with a matching name, and whose
120
* {@code Mixer} provides the respective line interface, will be returned. If no
121
* matching {@code Mixer.Info} object is found, or the mixer name is not
122
* specified, the first mixer from the resulting list, which provides the
123
* respective line interface, will be returned.
124
* <p>
125
* For example, the property {@code javax.sound.sampled.Clip} with a value
126
* {@code "com.sun.media.sound.MixerProvider#SunClip"} will have the following
127
* consequences when {@code getLine} is called requesting a {@code Clip}
128
* instance: if the class {@code com.sun.media.sound.MixerProvider} exists in
129
* the list of installed mixer providers, the first {@code Clip} from the first
130
* mixer with name {@code "SunClip"} will be returned. If it cannot be found,
131
* the first {@code Clip} from the first mixer of the specified provider will be
132
* returned, regardless of name. If there is none, the first {@code Clip} from
133
* the first {@code Mixer} with name {@code "SunClip"} in the list of all mixers
134
* (as returned by {@code getMixerInfo}) will be returned, or, if not found, the
135
* first {@code Clip} of the first {@code Mixer} that can be found in the list
136
* of all mixers is returned. If that fails, too, an
137
* {@code IllegalArgumentException} is thrown.
138
*
139
* @author Kara Kytle
140
* @author Florian Bomers
141
* @author Matthias Pfisterer
142
* @author Kevin P. Smith
143
* @see AudioFormat
144
* @see AudioInputStream
145
* @see Mixer
146
* @see Line
147
* @see Line.Info
148
* @since 1.3
149
*/
150
public class AudioSystem {
151
152
/**
153
* An integer that stands for an unknown numeric value. This value is
154
* appropriate only for signed quantities that do not normally take negative
155
* values. Examples include file sizes, frame sizes, buffer sizes, and
156
* sample rates. A number of Java Sound constructors accept a value of
157
* {@code NOT_SPECIFIED} for such parameters. Other methods may also accept
158
* or return this value, as documented.
159
*/
160
public static final int NOT_SPECIFIED = -1;
161
162
/**
163
* Private no-args constructor for ensuring against instantiation.
164
*/
165
private AudioSystem() {
166
}
167
168
/**
169
* Obtains an array of mixer info objects that represents the set of audio
170
* mixers that are currently installed on the system.
171
*
172
* @return an array of info objects for the currently installed mixers. If
173
* no mixers are available on the system, an array of length 0 is
174
* returned.
175
* @see #getMixer
176
*/
177
public static Mixer.Info[] getMixerInfo() {
178
179
List<Mixer.Info> infos = getMixerInfoList();
180
Mixer.Info[] allInfos = infos.toArray(new Mixer.Info[infos.size()]);
181
return allInfos;
182
}
183
184
/**
185
* Obtains the requested audio mixer.
186
*
187
* @param info a {@code Mixer.Info} object representing the desired mixer,
188
* or {@code null} for the system default mixer
189
* @return the requested mixer
190
* @throws SecurityException if the requested mixer is unavailable because
191
* of security restrictions
192
* @throws IllegalArgumentException if the info object does not represent a
193
* mixer installed on the system
194
* @see #getMixerInfo
195
*/
196
public static Mixer getMixer(final Mixer.Info info) {
197
for (final MixerProvider provider : getMixerProviders()) {
198
try {
199
return provider.getMixer(info);
200
} catch (IllegalArgumentException | NullPointerException ignored) {
201
// The MixerProvider.getMixer(null) should return default Mixer,
202
// This behaviour was assumed from the beginning, but strictly
203
// specified only in the jdk9. Since the jdk1.1.5 we skipped
204
// NPE for some reason and therefore skipped some
205
// implementations of MixerProviders, which throw NPE. To keep
206
// support of such implementations, we still ignore NPE.
207
}
208
}
209
throw new IllegalArgumentException(
210
String.format("Mixer not supported: %s", info));
211
}
212
213
//$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
214
215
/**
216
* Obtains information about all source lines of a particular type that are
217
* supported by the installed mixers.
218
*
219
* @param info a {@code Line.Info} object that specifies the kind of lines
220
* about which information is requested
221
* @return an array of {@code Line.Info} objects describing source lines
222
* matching the type requested. If no matching source lines are
223
* supported, an array of length 0 is returned.
224
* @see Mixer#getSourceLineInfo(Line.Info)
225
*/
226
public static Line.Info[] getSourceLineInfo(Line.Info info) {
227
228
Vector<Line.Info> vector = new Vector<>();
229
Line.Info[] currentInfoArray;
230
231
Mixer mixer;
232
Line.Info fullInfo = null;
233
Mixer.Info[] infoArray = getMixerInfo();
234
235
for (int i = 0; i < infoArray.length; i++) {
236
237
mixer = getMixer(infoArray[i]);
238
239
currentInfoArray = mixer.getSourceLineInfo(info);
240
for (int j = 0; j < currentInfoArray.length; j++) {
241
vector.addElement(currentInfoArray[j]);
242
}
243
}
244
245
Line.Info[] returnedArray = new Line.Info[vector.size()];
246
247
for (int i = 0; i < returnedArray.length; i++) {
248
returnedArray[i] = vector.get(i);
249
}
250
251
return returnedArray;
252
}
253
254
/**
255
* Obtains information about all target lines of a particular type that are
256
* supported by the installed mixers.
257
*
258
* @param info a {@code Line.Info} object that specifies the kind of lines
259
* about which information is requested
260
* @return an array of {@code Line.Info} objects describing target lines
261
* matching the type requested. If no matching target lines are
262
* supported, an array of length 0 is returned.
263
* @see Mixer#getTargetLineInfo(Line.Info)
264
*/
265
public static Line.Info[] getTargetLineInfo(Line.Info info) {
266
267
Vector<Line.Info> vector = new Vector<>();
268
Line.Info[] currentInfoArray;
269
270
Mixer mixer;
271
Line.Info fullInfo = null;
272
Mixer.Info[] infoArray = getMixerInfo();
273
274
for (int i = 0; i < infoArray.length; i++) {
275
276
mixer = getMixer(infoArray[i]);
277
278
currentInfoArray = mixer.getTargetLineInfo(info);
279
for (int j = 0; j < currentInfoArray.length; j++) {
280
vector.addElement(currentInfoArray[j]);
281
}
282
}
283
284
Line.Info[] returnedArray = new Line.Info[vector.size()];
285
286
for (int i = 0; i < returnedArray.length; i++) {
287
returnedArray[i] = vector.get(i);
288
}
289
290
return returnedArray;
291
}
292
293
/**
294
* Indicates whether the system supports any lines that match the specified
295
* {@code Line.Info} object. A line is supported if any installed mixer
296
* supports it.
297
*
298
* @param info a {@code Line.Info} object describing the line for which
299
* support is queried
300
* @return {@code true} if at least one matching line is supported,
301
* otherwise {@code false}
302
* @see Mixer#isLineSupported(Line.Info)
303
*/
304
public static boolean isLineSupported(Line.Info info) {
305
306
Mixer mixer;
307
Mixer.Info[] infoArray = getMixerInfo();
308
309
for (int i = 0; i < infoArray.length; i++) {
310
311
if( infoArray[i] != null ) {
312
mixer = getMixer(infoArray[i]);
313
if (mixer.isLineSupported(info)) {
314
return true;
315
}
316
}
317
}
318
319
return false;
320
}
321
322
/**
323
* Obtains a line that matches the description in the specified
324
* {@code Line.Info} object.
325
* <p>
326
* If a {@code DataLine} is requested, and {@code info} is an instance of
327
* {@code DataLine.Info} specifying at least one fully qualified audio
328
* format, the last one will be used as the default format of the returned
329
* {@code DataLine}.
330
* <p>
331
* If system properties
332
* {@code javax.sound.sampled.Clip},
333
* {@code javax.sound.sampled.Port},
334
* {@code javax.sound.sampled.SourceDataLine} and
335
* {@code javax.sound.sampled.TargetDataLine} are defined or they are
336
* defined in the file "sound.properties", they are used to retrieve default
337
* lines. For details, refer to the {@link AudioSystem class description}.
338
*
339
* If the respective property is not set, or the mixer requested in the
340
* property is not installed or does not provide the requested line, all
341
* installed mixers are queried for the requested line type. A Line will be
342
* returned from the first mixer providing the requested line type.
343
*
344
* @param info a {@code Line.Info} object describing the desired kind of
345
* line
346
* @return a line of the requested kind
347
* @throws LineUnavailableException if a matching line is not available due
348
* to resource restrictions
349
* @throws SecurityException if a matching line is not available due to
350
* security restrictions
351
* @throws IllegalArgumentException if the system does not support at least
352
* one line matching the specified {@code Line.Info} object through
353
* any installed mixer
354
*/
355
public static Line getLine(Line.Info info) throws LineUnavailableException {
356
LineUnavailableException lue = null;
357
List<MixerProvider> providers = getMixerProviders();
358
359
360
// 1: try from default mixer for this line class
361
try {
362
Mixer mixer = getDefaultMixer(providers, info);
363
if (mixer != null && mixer.isLineSupported(info)) {
364
return mixer.getLine(info);
365
}
366
} catch (LineUnavailableException e) {
367
lue = e;
368
} catch (IllegalArgumentException iae) {
369
// must not happen... but better to catch it here,
370
// if plug-ins are badly written
371
}
372
373
374
// 2: if that doesn't work, try to find any mixing mixer
375
for(int i = 0; i < providers.size(); i++) {
376
MixerProvider provider = providers.get(i);
377
Mixer.Info[] infos = provider.getMixerInfo();
378
379
for (int j = 0; j < infos.length; j++) {
380
try {
381
Mixer mixer = provider.getMixer(infos[j]);
382
// see if this is an appropriate mixer which can mix
383
if (isAppropriateMixer(mixer, info, true)) {
384
return mixer.getLine(info);
385
}
386
} catch (LineUnavailableException e) {
387
lue = e;
388
} catch (IllegalArgumentException iae) {
389
// must not happen... but better to catch it here,
390
// if plug-ins are badly written
391
}
392
}
393
}
394
395
396
// 3: if that didn't work, try to find any non-mixing mixer
397
for(int i = 0; i < providers.size(); i++) {
398
MixerProvider provider = providers.get(i);
399
Mixer.Info[] infos = provider.getMixerInfo();
400
for (int j = 0; j < infos.length; j++) {
401
try {
402
Mixer mixer = provider.getMixer(infos[j]);
403
// see if this is an appropriate mixer which can mix
404
if (isAppropriateMixer(mixer, info, false)) {
405
return mixer.getLine(info);
406
}
407
} catch (LineUnavailableException e) {
408
lue = e;
409
} catch (IllegalArgumentException iae) {
410
// must not happen... but better to catch it here,
411
// if plug-ins are badly written
412
}
413
}
414
}
415
416
// if this line was supported but was not available, throw the last
417
// LineUnavailableException we got (??).
418
if (lue != null) {
419
throw lue;
420
}
421
422
// otherwise, the requested line was not supported, so throw
423
// an Illegal argument exception
424
throw new IllegalArgumentException("No line matching " +
425
info.toString() + " is supported.");
426
}
427
428
/**
429
* Obtains a clip that can be used for playing back an audio file or an
430
* audio stream. The returned clip will be provided by the default system
431
* mixer, or, if not possible, by any other mixer installed in the system
432
* that supports a {@code Clip} object.
433
* <p>
434
* The returned clip must be opened with the {@code open(AudioFormat)} or
435
* {@code open(AudioInputStream)} method.
436
* <p>
437
* This is a high-level method that uses {@code getMixer} and
438
* {@code getLine} internally.
439
* <p>
440
* If the system property {@code javax.sound.sampled.Clip} is defined or it
441
* is defined in the file "sound.properties", it is used to retrieve the
442
* default clip. For details, refer to the
443
* {@link AudioSystem class description}.
444
*
445
* @return the desired clip object
446
* @throws LineUnavailableException if a clip object is not available due to
447
* resource restrictions
448
* @throws SecurityException if a clip object is not available due to
449
* security restrictions
450
* @throws IllegalArgumentException if the system does not support at least
451
* one clip instance through any installed mixer
452
* @see #getClip(Mixer.Info)
453
* @since 1.5
454
*/
455
public static Clip getClip() throws LineUnavailableException{
456
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
457
AudioSystem.NOT_SPECIFIED,
458
16, 2, 4,
459
AudioSystem.NOT_SPECIFIED, true);
460
DataLine.Info info = new DataLine.Info(Clip.class, format);
461
return (Clip) AudioSystem.getLine(info);
462
}
463
464
/**
465
* Obtains a clip from the specified mixer that can be used for playing back
466
* an audio file or an audio stream.
467
* <p>
468
* The returned clip must be opened with the {@code open(AudioFormat)} or
469
* {@code open(AudioInputStream)} method.
470
* <p>
471
* This is a high-level method that uses {@code getMixer} and
472
* {@code getLine} internally.
473
*
474
* @param mixerInfo a {@code Mixer.Info} object representing the desired
475
* mixer, or {@code null} for the system default mixer
476
* @return a clip object from the specified mixer
477
* @throws LineUnavailableException if a clip is not available from this
478
* mixer due to resource restrictions
479
* @throws SecurityException if a clip is not available from this mixer due
480
* to security restrictions
481
* @throws IllegalArgumentException if the system does not support at least
482
* one clip through the specified mixer
483
* @see #getClip()
484
* @since 1.5
485
*/
486
public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{
487
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
488
AudioSystem.NOT_SPECIFIED,
489
16, 2, 4,
490
AudioSystem.NOT_SPECIFIED, true);
491
DataLine.Info info = new DataLine.Info(Clip.class, format);
492
Mixer mixer = AudioSystem.getMixer(mixerInfo);
493
return (Clip) mixer.getLine(info);
494
}
495
496
/**
497
* Obtains a source data line that can be used for playing back audio data
498
* in the format specified by the {@code AudioFormat} object. The returned
499
* line will be provided by the default system mixer, or, if not possible,
500
* by any other mixer installed in the system that supports a matching
501
* {@code SourceDataLine} object.
502
* <p>
503
* The returned line should be opened with the {@code open(AudioFormat)} or
504
* {@code open(AudioFormat, int)} method.
505
* <p>
506
* This is a high-level method that uses {@code getMixer} and
507
* {@code getLine} internally.
508
* <p>
509
* The returned {@code SourceDataLine}'s default audio format will be
510
* initialized with {@code format}.
511
* <p>
512
* If the system property {@code javax.sound.sampled.SourceDataLine} is
513
* defined or it is defined in the file "sound.properties", it is used to
514
* retrieve the default source data line. For details, refer to the
515
* {@link AudioSystem class description}.
516
*
517
* @param format an {@code AudioFormat} object specifying the supported
518
* audio format of the returned line, or {@code null} for any audio
519
* format
520
* @return the desired {@code SourceDataLine} object
521
* @throws LineUnavailableException if a matching source data line is not
522
* available due to resource restrictions
523
* @throws SecurityException if a matching source data line is not available
524
* due to security restrictions
525
* @throws IllegalArgumentException if the system does not support at least
526
* one source data line supporting the specified audio format
527
* through any installed mixer
528
* @see #getSourceDataLine(AudioFormat, Mixer.Info)
529
* @since 1.5
530
*/
531
public static SourceDataLine getSourceDataLine(AudioFormat format)
532
throws LineUnavailableException{
533
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
534
return (SourceDataLine) AudioSystem.getLine(info);
535
}
536
537
/**
538
* Obtains a source data line that can be used for playing back audio data
539
* in the format specified by the {@code AudioFormat} object, provided by
540
* the mixer specified by the {@code Mixer.Info} object.
541
* <p>
542
* The returned line should be opened with the {@code open(AudioFormat)} or
543
* {@code open(AudioFormat, int)} method.
544
* <p>
545
* This is a high-level method that uses {@code getMixer} and
546
* {@code getLine} internally.
547
* <p>
548
* The returned {@code SourceDataLine}'s default audio format will be
549
* initialized with {@code format}.
550
*
551
* @param format an {@code AudioFormat} object specifying the supported
552
* audio format of the returned line, or {@code null} for any audio
553
* format
554
* @param mixerinfo a {@code Mixer.Info} object representing the desired
555
* mixer, or {@code null} for the system default mixer
556
* @return the desired {@code SourceDataLine} object
557
* @throws LineUnavailableException if a matching source data line is not
558
* available from the specified mixer due to resource restrictions
559
* @throws SecurityException if a matching source data line is not available
560
* from the specified mixer due to security restrictions
561
* @throws IllegalArgumentException if the specified mixer does not support
562
* at least one source data line supporting the specified audio
563
* format
564
* @see #getSourceDataLine(AudioFormat)
565
* @since 1.5
566
*/
567
public static SourceDataLine getSourceDataLine(AudioFormat format,
568
Mixer.Info mixerinfo)
569
throws LineUnavailableException{
570
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
571
Mixer mixer = AudioSystem.getMixer(mixerinfo);
572
return (SourceDataLine) mixer.getLine(info);
573
}
574
575
/**
576
* Obtains a target data line that can be used for recording audio data in
577
* the format specified by the {@code AudioFormat} object. The returned line
578
* will be provided by the default system mixer, or, if not possible, by any
579
* other mixer installed in the system that supports a matching
580
* {@code TargetDataLine} object.
581
* <p>
582
* The returned line should be opened with the {@code open(AudioFormat)} or
583
* {@code open(AudioFormat, int)} method.
584
* <p>
585
* This is a high-level method that uses {@code getMixer} and
586
* {@code getLine} internally.
587
* <p>
588
* The returned {@code TargetDataLine}'s default audio format will be
589
* initialized with {@code format}.
590
* <p>
591
* If the system property {@code javax.sound.sampled.TargetDataLine} is
592
* defined or it is defined in the file "sound.properties", it is used to
593
* retrieve the default target data line. For details, refer to the
594
* {@link AudioSystem class description}.
595
*
596
* @param format an {@code AudioFormat} object specifying the supported
597
* audio format of the returned line, or {@code null} for any audio
598
* format
599
* @return the desired {@code TargetDataLine} object
600
* @throws LineUnavailableException if a matching target data line is not
601
* available due to resource restrictions
602
* @throws SecurityException if a matching target data line is not available
603
* due to security restrictions
604
* @throws IllegalArgumentException if the system does not support at least
605
* one target data line supporting the specified audio format
606
* through any installed mixer
607
* @see #getTargetDataLine(AudioFormat, Mixer.Info)
608
* @see AudioPermission
609
* @since 1.5
610
*/
611
public static TargetDataLine getTargetDataLine(AudioFormat format)
612
throws LineUnavailableException{
613
614
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
615
return (TargetDataLine) AudioSystem.getLine(info);
616
}
617
618
/**
619
* Obtains a target data line that can be used for recording audio data in
620
* the format specified by the {@code AudioFormat} object, provided by the
621
* mixer specified by the {@code Mixer.Info} object.
622
* <p>
623
* The returned line should be opened with the {@code open(AudioFormat)} or
624
* {@code open(AudioFormat, int)} method.
625
* <p>
626
* This is a high-level method that uses {@code getMixer} and
627
* {@code getLine} internally.
628
* <p>
629
* The returned {@code TargetDataLine}'s default audio format will be
630
* initialized with {@code format}.
631
*
632
* @param format an {@code AudioFormat} object specifying the supported
633
* audio format of the returned line, or {@code null} for any audio
634
* format
635
* @param mixerinfo a {@code Mixer.Info} object representing the desired
636
* mixer, or {@code null} for the system default mixer
637
* @return the desired {@code TargetDataLine} object
638
* @throws LineUnavailableException if a matching target data line is not
639
* available from the specified mixer due to resource restrictions
640
* @throws SecurityException if a matching target data line is not available
641
* from the specified mixer due to security restrictions
642
* @throws IllegalArgumentException if the specified mixer does not support
643
* at least one target data line supporting the specified audio
644
* format
645
* @see #getTargetDataLine(AudioFormat)
646
* @see AudioPermission
647
* @since 1.5
648
*/
649
public static TargetDataLine getTargetDataLine(AudioFormat format,
650
Mixer.Info mixerinfo)
651
throws LineUnavailableException {
652
653
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
654
Mixer mixer = AudioSystem.getMixer(mixerinfo);
655
return (TargetDataLine) mixer.getLine(info);
656
}
657
658
// $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
659
660
/**
661
* Obtains the encodings that the system can obtain from an audio input
662
* stream with the specified encoding using the set of installed format
663
* converters.
664
*
665
* @param sourceEncoding the encoding for which conversion support is
666
* queried
667
* @return array of encodings. If {@code sourceEncoding} is not supported,
668
* an array of length 0 is returned. Otherwise, the array will have
669
* a length of at least 1, representing {@code sourceEncoding}
670
* (no conversion).
671
* @throws NullPointerException if {@code sourceEncoding} is {@code null}
672
*/
673
public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
674
Objects.requireNonNull(sourceEncoding);
675
676
List<FormatConversionProvider> codecs = getFormatConversionProviders();
677
Vector<AudioFormat.Encoding> encodings = new Vector<>();
678
679
AudioFormat.Encoding[] encs = null;
680
681
// gather from all the codecs
682
for(int i=0; i<codecs.size(); i++ ) {
683
FormatConversionProvider codec = codecs.get(i);
684
if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
685
encs = codec.getTargetEncodings();
686
for (int j = 0; j < encs.length; j++) {
687
encodings.addElement( encs[j] );
688
}
689
}
690
}
691
if (!encodings.contains(sourceEncoding)) {
692
encodings.addElement(sourceEncoding);
693
}
694
695
return encodings.toArray(new AudioFormat.Encoding[encodings.size()]);
696
}
697
698
// $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
699
700
/**
701
* Obtains the encodings that the system can obtain from an audio input
702
* stream with the specified format using the set of installed format
703
* converters.
704
*
705
* @param sourceFormat the audio format for which conversion is queried
706
* @return array of encodings. If {@code sourceFormat}is not supported, an
707
* array of length 0 is returned. Otherwise, the array will have a
708
* length of at least 1, representing the encoding of
709
* {@code sourceFormat} (no conversion).
710
* @throws NullPointerException if {@code sourceFormat} is {@code null}
711
*/
712
public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
713
Objects.requireNonNull(sourceFormat);
714
715
List<FormatConversionProvider> codecs = getFormatConversionProviders();
716
List<AudioFormat.Encoding> encs = new ArrayList<>();
717
718
// gather from all the codecs
719
for (final FormatConversionProvider codec : codecs) {
720
Collections.addAll(encs, codec.getTargetEncodings(sourceFormat));
721
}
722
723
if (!encs.contains(sourceFormat.getEncoding())) {
724
encs.add(sourceFormat.getEncoding());
725
}
726
727
return encs.toArray(new AudioFormat.Encoding[encs.size()]);
728
}
729
730
/**
731
* Indicates whether an audio input stream of the specified encoding can be
732
* obtained from an audio input stream that has the specified format.
733
*
734
* @param targetEncoding the desired encoding after conversion
735
* @param sourceFormat the audio format before conversion
736
* @return {@code true} if the conversion is supported, otherwise
737
* {@code false}
738
* @throws NullPointerException if {@code targetEncoding} or
739
* {@code sourceFormat} are {@code null}
740
*/
741
public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
742
Objects.requireNonNull(targetEncoding);
743
Objects.requireNonNull(sourceFormat);
744
if (sourceFormat.getEncoding().equals(targetEncoding)) {
745
return true;
746
}
747
748
List<FormatConversionProvider> codecs = getFormatConversionProviders();
749
750
for(int i=0; i<codecs.size(); i++ ) {
751
FormatConversionProvider codec = codecs.get(i);
752
if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {
753
return true;
754
}
755
}
756
return false;
757
}
758
759
/**
760
* Obtains an audio input stream of the indicated encoding, by converting
761
* the provided audio input stream.
762
*
763
* @param targetEncoding the desired encoding after conversion
764
* @param sourceStream the stream to be converted
765
* @return an audio input stream of the indicated encoding
766
* @throws IllegalArgumentException if the conversion is not supported
767
* @throws NullPointerException if {@code targetEncoding} or
768
* {@code sourceStream} are {@code null}
769
* @see #getTargetEncodings(AudioFormat.Encoding)
770
* @see #getTargetEncodings(AudioFormat)
771
* @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
772
* @see #getAudioInputStream(AudioFormat, AudioInputStream)
773
*/
774
public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
775
AudioInputStream sourceStream) {
776
Objects.requireNonNull(targetEncoding);
777
Objects.requireNonNull(sourceStream);
778
if (sourceStream.getFormat().getEncoding().equals(targetEncoding)) {
779
return sourceStream;
780
}
781
782
List<FormatConversionProvider> codecs = getFormatConversionProviders();
783
784
for(int i = 0; i < codecs.size(); i++) {
785
FormatConversionProvider codec = codecs.get(i);
786
if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
787
return codec.getAudioInputStream( targetEncoding, sourceStream );
788
}
789
}
790
// we ran out of options, throw an exception
791
throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
792
}
793
794
/**
795
* Obtains the formats that have a particular encoding and that the system
796
* can obtain from a stream of the specified format using the set of
797
* installed format converters.
798
*
799
* @param targetEncoding the desired encoding after conversion
800
* @param sourceFormat the audio format before conversion
801
* @return array of formats. If no formats of the specified encoding are
802
* supported, an array of length 0 is returned.
803
* @throws NullPointerException if {@code targetEncoding} or
804
* {@code sourceFormat} are {@code null}
805
*/
806
public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
807
Objects.requireNonNull(targetEncoding);
808
Objects.requireNonNull(sourceFormat);
809
810
List<FormatConversionProvider> codecs = getFormatConversionProviders();
811
List<AudioFormat> formats = new ArrayList<>();
812
813
boolean matchFound = false;
814
// gather from all the codecs
815
for (final FormatConversionProvider codec : codecs) {
816
AudioFormat[] elements = codec
817
.getTargetFormats(targetEncoding, sourceFormat);
818
for (AudioFormat format : elements) {
819
formats.add(format);
820
if (sourceFormat.matches(format)) {
821
matchFound = true;
822
}
823
}
824
}
825
826
if (targetEncoding.equals(sourceFormat.getEncoding())) {
827
if (!matchFound) {
828
formats.add(sourceFormat);
829
}
830
}
831
return formats.toArray(new AudioFormat[formats.size()]);
832
}
833
834
/**
835
* Indicates whether an audio input stream of a specified format can be
836
* obtained from an audio input stream of another specified format.
837
*
838
* @param targetFormat the desired audio format after conversion
839
* @param sourceFormat the audio format before conversion
840
* @return {@code true} if the conversion is supported, otherwise
841
* {@code false}
842
* @throws NullPointerException if {@code targetFormat} or
843
* {@code sourceFormat} are {@code null}
844
*/
845
public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {
846
Objects.requireNonNull(targetFormat);
847
Objects.requireNonNull(sourceFormat);
848
if (sourceFormat.matches(targetFormat)) {
849
return true;
850
}
851
852
List<FormatConversionProvider> codecs = getFormatConversionProviders();
853
854
for(int i=0; i<codecs.size(); i++ ) {
855
FormatConversionProvider codec = codecs.get(i);
856
if(codec.isConversionSupported(targetFormat, sourceFormat) ) {
857
return true;
858
}
859
}
860
return false;
861
}
862
863
/**
864
* Obtains an audio input stream of the indicated format, by converting the
865
* provided audio input stream.
866
*
867
* @param targetFormat the desired audio format after conversion
868
* @param sourceStream the stream to be converted
869
* @return an audio input stream of the indicated format
870
* @throws IllegalArgumentException if the conversion is not supported
871
* @throws NullPointerException if {@code targetFormat} or
872
* {@code sourceStream} are {@code null}
873
* @see #getTargetEncodings(AudioFormat)
874
* @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
875
* @see #isConversionSupported(AudioFormat, AudioFormat)
876
* @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
877
*/
878
public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
879
AudioInputStream sourceStream) {
880
if (sourceStream.getFormat().matches(targetFormat)) {
881
return sourceStream;
882
}
883
884
List<FormatConversionProvider> codecs = getFormatConversionProviders();
885
886
for(int i = 0; i < codecs.size(); i++) {
887
FormatConversionProvider codec = codecs.get(i);
888
if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
889
return codec.getAudioInputStream(targetFormat,sourceStream);
890
}
891
}
892
893
// we ran out of options...
894
throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
895
}
896
897
/**
898
* Obtains the audio file format of the provided input stream. The stream
899
* must point to valid audio file data. The implementation of this method
900
* may require multiple parsers to examine the stream to determine whether
901
* they support it. These parsers must be able to mark the stream, read
902
* enough data to determine whether they support the stream, and reset the
903
* stream's read pointer to its original position. If the input stream does
904
* not support these operations, this method may fail with an
905
* {@code IOException}.
906
*
907
* @param stream the input stream from which file format information should
908
* be extracted
909
* @return an {@code AudioFileFormat} object describing the stream's audio
910
* file format
911
* @throws UnsupportedAudioFileException if the stream does not point to
912
* valid audio file data recognized by the system
913
* @throws IOException if an input/output exception occurs
914
* @throws NullPointerException if {@code stream} is {@code null}
915
* @see InputStream#markSupported
916
* @see InputStream#mark
917
*/
918
public static AudioFileFormat getAudioFileFormat(final InputStream stream)
919
throws UnsupportedAudioFileException, IOException {
920
Objects.requireNonNull(stream);
921
922
for (final AudioFileReader reader : getAudioFileReaders()) {
923
try {
924
return reader.getAudioFileFormat(stream);
925
} catch (final UnsupportedAudioFileException ignored) {
926
}
927
}
928
throw new UnsupportedAudioFileException("Stream of unsupported format");
929
}
930
931
/**
932
* Obtains the audio file format of the specified {@code URL}. The
933
* {@code URL} must point to valid audio file data.
934
*
935
* @param url the {@code URL} from which file format information should be
936
* extracted
937
* @return an {@code AudioFileFormat} object describing the audio file
938
* format
939
* @throws UnsupportedAudioFileException if the {@code URL} does not point
940
* to valid audio file data recognized by the system
941
* @throws IOException if an input/output exception occurs
942
* @throws NullPointerException if {@code url} is {@code null}
943
*/
944
public static AudioFileFormat getAudioFileFormat(final URL url)
945
throws UnsupportedAudioFileException, IOException {
946
Objects.requireNonNull(url);
947
948
for (final AudioFileReader reader : getAudioFileReaders()) {
949
try {
950
return reader.getAudioFileFormat(url);
951
} catch (final UnsupportedAudioFileException ignored) {
952
}
953
}
954
throw new UnsupportedAudioFileException("URL of unsupported format");
955
}
956
957
/**
958
* Obtains the audio file format of the specified {@code File}. The
959
* {@code File} must point to valid audio file data.
960
*
961
* @param file the {@code File} from which file format information should
962
* be extracted
963
* @return an {@code AudioFileFormat} object describing the audio file
964
* format
965
* @throws UnsupportedAudioFileException if the {@code File} does not point
966
* to valid audio file data recognized by the system
967
* @throws IOException if an I/O exception occurs
968
* @throws NullPointerException if {@code file} is {@code null}
969
*/
970
public static AudioFileFormat getAudioFileFormat(final File file)
971
throws UnsupportedAudioFileException, IOException {
972
Objects.requireNonNull(file);
973
974
for (final AudioFileReader reader : getAudioFileReaders()) {
975
try {
976
return reader.getAudioFileFormat(file);
977
} catch (final UnsupportedAudioFileException ignored) {
978
}
979
}
980
throw new UnsupportedAudioFileException("File of unsupported format");
981
}
982
983
/**
984
* Obtains an audio input stream from the provided input stream. The stream
985
* must point to valid audio file data. The implementation of this method
986
* may require multiple parsers to examine the stream to determine whether
987
* they support it. These parsers must be able to mark the stream, read
988
* enough data to determine whether they support the stream, and reset the
989
* stream's read pointer to its original position. If the input stream does
990
* not support these operation, this method may fail with an
991
* {@code IOException}.
992
*
993
* @param stream the input stream from which the {@code AudioInputStream}
994
* should be constructed
995
* @return an {@code AudioInputStream} object based on the audio file data
996
* contained in the input stream
997
* @throws UnsupportedAudioFileException if the stream does not point to
998
* valid audio file data recognized by the system
999
* @throws IOException if an I/O exception occurs
1000
* @throws NullPointerException if {@code stream} is {@code null}
1001
* @see InputStream#markSupported
1002
* @see InputStream#mark
1003
*/
1004
public static AudioInputStream getAudioInputStream(final InputStream stream)
1005
throws UnsupportedAudioFileException, IOException {
1006
Objects.requireNonNull(stream);
1007
1008
for (final AudioFileReader reader : getAudioFileReaders()) {
1009
try {
1010
return reader.getAudioInputStream(stream);
1011
} catch (final UnsupportedAudioFileException ignored) {
1012
}
1013
}
1014
throw new UnsupportedAudioFileException("Stream of unsupported format");
1015
}
1016
1017
/**
1018
* Obtains an audio input stream from the {@code URL} provided. The
1019
* {@code URL} must point to valid audio file data.
1020
*
1021
* @param url the {@code URL} for which the {@code AudioInputStream} should
1022
* be constructed
1023
* @return an {@code AudioInputStream} object based on the audio file data
1024
* pointed to by the {@code URL}
1025
* @throws UnsupportedAudioFileException if the {@code URL} does not point
1026
* to valid audio file data recognized by the system
1027
* @throws IOException if an I/O exception occurs
1028
* @throws NullPointerException if {@code url} is {@code null}
1029
*/
1030
public static AudioInputStream getAudioInputStream(final URL url)
1031
throws UnsupportedAudioFileException, IOException {
1032
Objects.requireNonNull(url);
1033
1034
for (final AudioFileReader reader : getAudioFileReaders()) {
1035
try {
1036
return reader.getAudioInputStream(url);
1037
} catch (final UnsupportedAudioFileException ignored) {
1038
}
1039
}
1040
throw new UnsupportedAudioFileException("URL of unsupported format");
1041
}
1042
1043
/**
1044
* Obtains an audio input stream from the provided {@code File}. The
1045
* {@code File} must point to valid audio file data.
1046
*
1047
* @param file the {@code File} for which the {@code AudioInputStream}
1048
* should be constructed
1049
* @return an {@code AudioInputStream} object based on the audio file data
1050
* pointed to by the {@code File}
1051
* @throws UnsupportedAudioFileException if the {@code File} does not point
1052
* to valid audio file data recognized by the system
1053
* @throws IOException if an I/O exception occurs
1054
* @throws NullPointerException if {@code file} is {@code null}
1055
*/
1056
public static AudioInputStream getAudioInputStream(final File file)
1057
throws UnsupportedAudioFileException, IOException {
1058
Objects.requireNonNull(file);
1059
1060
for (final AudioFileReader reader : getAudioFileReaders()) {
1061
try {
1062
return reader.getAudioInputStream(file);
1063
} catch (final UnsupportedAudioFileException ignored) {
1064
}
1065
}
1066
throw new UnsupportedAudioFileException("File of unsupported format");
1067
}
1068
1069
/**
1070
* Obtains the file types for which file writing support is provided by the
1071
* system.
1072
*
1073
* @return array of unique file types. If no file types are supported, an
1074
* array of length 0 is returned.
1075
*/
1076
public static AudioFileFormat.Type[] getAudioFileTypes() {
1077
List<AudioFileWriter> providers = getAudioFileWriters();
1078
Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1079
1080
for(int i=0; i < providers.size(); i++) {
1081
AudioFileWriter writer = providers.get(i);
1082
AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();
1083
for(int j=0; j < fileTypes.length; j++) {
1084
returnTypesSet.add(fileTypes[j]);
1085
}
1086
}
1087
AudioFileFormat.Type[] returnTypes =
1088
returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1089
return returnTypes;
1090
}
1091
1092
/**
1093
* Indicates whether file writing support for the specified file type is
1094
* provided by the system.
1095
*
1096
* @param fileType the file type for which write capabilities are queried
1097
* @return {@code true} if the file type is supported, otherwise
1098
* {@code false}
1099
* @throws NullPointerException if {@code fileType} is {@code null}
1100
*/
1101
public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1102
Objects.requireNonNull(fileType);
1103
List<AudioFileWriter> providers = getAudioFileWriters();
1104
1105
for(int i=0; i < providers.size(); i++) {
1106
AudioFileWriter writer = providers.get(i);
1107
if (writer.isFileTypeSupported(fileType)) {
1108
return true;
1109
}
1110
}
1111
return false;
1112
}
1113
1114
/**
1115
* Obtains the file types that the system can write from the audio input
1116
* stream specified.
1117
*
1118
* @param stream the audio input stream for which audio file type support
1119
* is queried
1120
* @return array of file types. If no file types are supported, an array of
1121
* length 0 is returned.
1122
* @throws NullPointerException if {@code stream} is {@code null}
1123
*/
1124
public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1125
Objects.requireNonNull(stream);
1126
List<AudioFileWriter> providers = getAudioFileWriters();
1127
Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1128
1129
for(int i=0; i < providers.size(); i++) {
1130
AudioFileWriter writer = providers.get(i);
1131
AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1132
for(int j=0; j < fileTypes.length; j++) {
1133
returnTypesSet.add(fileTypes[j]);
1134
}
1135
}
1136
AudioFileFormat.Type[] returnTypes =
1137
returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1138
return returnTypes;
1139
}
1140
1141
/**
1142
* Indicates whether an audio file of the specified file type can be written
1143
* from the indicated audio input stream.
1144
*
1145
* @param fileType the file type for which write capabilities are queried
1146
* @param stream the stream for which file-writing support is queried
1147
* @return {@code true} if the file type is supported for this audio input
1148
* stream, otherwise {@code false}
1149
* @throws NullPointerException if {@code fileType} or {@code stream} are
1150
* {@code null}
1151
*/
1152
public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1153
AudioInputStream stream) {
1154
Objects.requireNonNull(fileType);
1155
Objects.requireNonNull(stream);
1156
List<AudioFileWriter> providers = getAudioFileWriters();
1157
1158
for(int i=0; i < providers.size(); i++) {
1159
AudioFileWriter writer = providers.get(i);
1160
if(writer.isFileTypeSupported(fileType, stream)) {
1161
return true;
1162
}
1163
}
1164
return false;
1165
}
1166
1167
/**
1168
* Writes a stream of bytes representing an audio file of the specified file
1169
* type to the output stream provided. Some file types require that the
1170
* length be written into the file header; such files cannot be written from
1171
* start to finish unless the length is known in advance. An attempt to
1172
* write a file of such a type will fail with an {@code IOException} if the
1173
* length in the audio file type is {@code AudioSystem.NOT_SPECIFIED}.
1174
*
1175
* @param stream the audio input stream containing audio data to be written
1176
* to the file
1177
* @param fileType the kind of audio file to write
1178
* @param out the stream to which the file data should be written
1179
* @return the number of bytes written to the output stream
1180
* @throws IOException if an input/output exception occurs
1181
* @throws IllegalArgumentException if the file type is not supported by the
1182
* system
1183
* @throws NullPointerException if {@code stream} or {@code fileType} or
1184
* {@code out} are {@code null}
1185
* @see #isFileTypeSupported
1186
* @see #getAudioFileTypes
1187
*/
1188
public static int write(final AudioInputStream stream,
1189
final AudioFileFormat.Type fileType,
1190
final OutputStream out) throws IOException {
1191
Objects.requireNonNull(stream);
1192
Objects.requireNonNull(fileType);
1193
Objects.requireNonNull(out);
1194
1195
for (final AudioFileWriter writer : getAudioFileWriters()) {
1196
try {
1197
return writer.write(stream, fileType, out);
1198
} catch (final IllegalArgumentException ignored) {
1199
// thrown if this provider cannot write the stream, try next
1200
}
1201
}
1202
// "File type " + type + " not supported."
1203
throw new IllegalArgumentException(
1204
"could not write audio file: file type not supported: "
1205
+ fileType);
1206
}
1207
1208
/**
1209
* Writes a stream of bytes representing an audio file of the specified file
1210
* type to the external file provided.
1211
*
1212
* @param stream the audio input stream containing audio data to be written
1213
* to the file
1214
* @param fileType the kind of audio file to write
1215
* @param out the external file to which the file data should be written
1216
* @return the number of bytes written to the file
1217
* @throws IOException if an I/O exception occurs
1218
* @throws IllegalArgumentException if the file type is not supported by the
1219
* system
1220
* @throws NullPointerException if {@code stream} or {@code fileType} or
1221
* {@code out} are {@code null}
1222
* @see #isFileTypeSupported
1223
* @see #getAudioFileTypes
1224
*/
1225
public static int write(final AudioInputStream stream,
1226
final AudioFileFormat.Type fileType,
1227
final File out) throws IOException {
1228
Objects.requireNonNull(stream);
1229
Objects.requireNonNull(fileType);
1230
Objects.requireNonNull(out);
1231
1232
for (final AudioFileWriter writer : getAudioFileWriters()) {
1233
try {
1234
return writer.write(stream, fileType, out);
1235
} catch (final IllegalArgumentException ignored) {
1236
// thrown if this provider cannot write the stream, try next
1237
}
1238
}
1239
throw new IllegalArgumentException(
1240
"could not write audio file: file type not supported: "
1241
+ fileType);
1242
}
1243
1244
// METHODS FOR INTERNAL IMPLEMENTATION USE
1245
1246
/**
1247
* Obtains the list of MixerProviders currently installed on the system.
1248
*
1249
* @return the list of MixerProviders currently installed on the system
1250
*/
1251
@SuppressWarnings("unchecked")
1252
private static List<MixerProvider> getMixerProviders() {
1253
return (List<MixerProvider>) getProviders(MixerProvider.class);
1254
}
1255
1256
/**
1257
* Obtains the set of format converters (codecs, transcoders, etc.) that are
1258
* currently installed on the system.
1259
*
1260
* @return an array of {@link FormatConversionProvider} objects representing
1261
* the available format converters. If no format converters readers
1262
* are available on the system, an array of length 0 is returned.
1263
*/
1264
@SuppressWarnings("unchecked")
1265
private static List<FormatConversionProvider> getFormatConversionProviders() {
1266
return (List<FormatConversionProvider>) getProviders(FormatConversionProvider.class);
1267
}
1268
1269
/**
1270
* Obtains the set of audio file readers that are currently installed on the
1271
* system.
1272
*
1273
* @return a List of {@link AudioFileReader} objects representing the
1274
* installed audio file readers. If no audio file readers are
1275
* available on the system, an empty List is returned.
1276
*/
1277
@SuppressWarnings("unchecked")
1278
private static List<AudioFileReader> getAudioFileReaders() {
1279
return (List<AudioFileReader>)getProviders(AudioFileReader.class);
1280
}
1281
1282
/**
1283
* Obtains the set of audio file writers that are currently installed on the
1284
* system.
1285
*
1286
* @return a List of {@link AudioFileWriter} objects representing the
1287
* available audio file writers. If no audio file writers are
1288
* available on the system, an empty List is returned.
1289
*/
1290
@SuppressWarnings("unchecked")
1291
private static List<AudioFileWriter> getAudioFileWriters() {
1292
return (List<AudioFileWriter>)getProviders(AudioFileWriter.class);
1293
}
1294
1295
/**
1296
* Attempts to locate and return a default Mixer that provides lines of the
1297
* specified type.
1298
*
1299
* @param providers the installed mixer providers
1300
* @param info The requested line type TargetDataLine.class, Clip.class or
1301
* Port.class
1302
* @return a Mixer that matches the requirements, or null if no default
1303
* mixer found
1304
*/
1305
private static Mixer getDefaultMixer(List<MixerProvider> providers, Line.Info info) {
1306
Class<?> lineClass = info.getLineClass();
1307
String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);
1308
String instanceName = JDK13Services.getDefaultInstanceName(lineClass);
1309
Mixer mixer;
1310
1311
if (providerClassName != null) {
1312
MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1313
if (defaultProvider != null) {
1314
if (instanceName != null) {
1315
mixer = getNamedMixer(instanceName, defaultProvider, info);
1316
if (mixer != null) {
1317
return mixer;
1318
}
1319
} else {
1320
mixer = getFirstMixer(defaultProvider, info,
1321
false /* mixing not required*/);
1322
if (mixer != null) {
1323
return mixer;
1324
}
1325
}
1326
1327
}
1328
}
1329
1330
/*
1331
* - Provider class not specified, or
1332
* - provider class cannot be found, or
1333
* - provider class and instance specified and instance cannot be found
1334
* or is not appropriate
1335
*/
1336
if (instanceName != null) {
1337
mixer = getNamedMixer(instanceName, providers, info);
1338
if (mixer != null) {
1339
return mixer;
1340
}
1341
}
1342
1343
1344
/*
1345
* No defaults are specified, or if something is specified, everything
1346
* failed
1347
*/
1348
return null;
1349
}
1350
1351
/**
1352
* Return a MixerProvider of a given class from the list of MixerProviders.
1353
* This method never requires the returned Mixer to do mixing.
1354
*
1355
* @param providerClassName The class name of the provider to be returned
1356
* @param providers The list of MixerProviders that is searched
1357
* @return A MixerProvider of the requested class, or null if none is found
1358
*/
1359
private static MixerProvider getNamedProvider(String providerClassName,
1360
List<MixerProvider> providers) {
1361
for(int i = 0; i < providers.size(); i++) {
1362
MixerProvider provider = providers.get(i);
1363
if (provider.getClass().getName().equals(providerClassName)) {
1364
return provider;
1365
}
1366
}
1367
return null;
1368
}
1369
1370
/**
1371
* Return a Mixer with a given name from a given MixerProvider. This method
1372
* never requires the returned Mixer to do mixing.
1373
*
1374
* @param mixerName The name of the Mixer to be returned
1375
* @param provider The MixerProvider to check for Mixers
1376
* @param info The type of line the returned Mixer is required to support
1377
* @return A Mixer matching the requirements, or null if none is found
1378
*/
1379
private static Mixer getNamedMixer(String mixerName,
1380
MixerProvider provider,
1381
Line.Info info) {
1382
Mixer.Info[] infos = provider.getMixerInfo();
1383
for (int i = 0; i < infos.length; i++) {
1384
if (infos[i].getName().equals(mixerName)) {
1385
Mixer mixer = provider.getMixer(infos[i]);
1386
if (isAppropriateMixer(mixer, info, false)) {
1387
return mixer;
1388
}
1389
}
1390
}
1391
return null;
1392
}
1393
1394
/**
1395
* From a List of MixerProviders, return a Mixer with a given name. This
1396
* method never requires the returned Mixer to do mixing.
1397
*
1398
* @param mixerName The name of the Mixer to be returned
1399
* @param providers The List of MixerProviders to check for Mixers
1400
* @param info The type of line the returned Mixer is required to support
1401
* @return A Mixer matching the requirements, or null if none is found
1402
*/
1403
private static Mixer getNamedMixer(String mixerName,
1404
List<MixerProvider> providers,
1405
Line.Info info) {
1406
for(int i = 0; i < providers.size(); i++) {
1407
MixerProvider provider = providers.get(i);
1408
Mixer mixer = getNamedMixer(mixerName, provider, info);
1409
if (mixer != null) {
1410
return mixer;
1411
}
1412
}
1413
return null;
1414
}
1415
1416
/**
1417
* From a given MixerProvider, return the first appropriate Mixer.
1418
*
1419
* @param provider The MixerProvider to check for Mixers
1420
* @param info The type of line the returned Mixer is required to support
1421
* @param isMixingRequired If true, only Mixers that support mixing are
1422
* returned for line types of SourceDataLine and Clip
1423
* @return A Mixer that is considered appropriate, or null if none is found
1424
*/
1425
private static Mixer getFirstMixer(MixerProvider provider,
1426
Line.Info info,
1427
boolean isMixingRequired) {
1428
Mixer.Info[] infos = provider.getMixerInfo();
1429
for (int j = 0; j < infos.length; j++) {
1430
Mixer mixer = provider.getMixer(infos[j]);
1431
if (isAppropriateMixer(mixer, info, isMixingRequired)) {
1432
return mixer;
1433
}
1434
}
1435
return null;
1436
}
1437
1438
/**
1439
* Checks if a Mixer is appropriate. A Mixer is considered appropriate if it
1440
* support the given line type. If isMixingRequired is {@code true} and the
1441
* line type is an output one (SourceDataLine, Clip), the mixer is
1442
* appropriate if it supports at least 2 (concurrent) lines of the given
1443
* type.
1444
*
1445
* @param mixer The mixer to check
1446
* @param lineInfo The line to check
1447
* @param isMixingRequired Is the mixing required or not
1448
* @return {@code true} if the mixer is considered appropriate according to
1449
* the rules given above, {@code false} otherwise
1450
*/
1451
private static boolean isAppropriateMixer(Mixer mixer,
1452
Line.Info lineInfo,
1453
boolean isMixingRequired) {
1454
if (! mixer.isLineSupported(lineInfo)) {
1455
return false;
1456
}
1457
Class<?> lineClass = lineInfo.getLineClass();
1458
if (isMixingRequired
1459
&& (SourceDataLine.class.isAssignableFrom(lineClass) ||
1460
Clip.class.isAssignableFrom(lineClass))) {
1461
int maxLines = mixer.getMaxLines(lineInfo);
1462
return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1463
}
1464
return true;
1465
}
1466
1467
/**
1468
* Like getMixerInfo, but return List.
1469
*
1470
* @return a List of info objects for the currently installed mixers. If no
1471
* mixers are available on the system, an empty List is returned.
1472
* @see #getMixerInfo()
1473
*/
1474
private static List<Mixer.Info> getMixerInfoList() {
1475
List<MixerProvider> providers = getMixerProviders();
1476
return getMixerInfoList(providers);
1477
}
1478
1479
/**
1480
* Like getMixerInfo, but return List.
1481
*
1482
* @param providers The list of MixerProviders
1483
* @return a List of info objects for the currently installed mixers. If no
1484
* mixers are available on the system, an empty List is returned.
1485
* @see #getMixerInfo()
1486
*/
1487
private static List<Mixer.Info> getMixerInfoList(List<MixerProvider> providers) {
1488
List<Mixer.Info> infos = new ArrayList<>();
1489
1490
Mixer.Info[] someInfos; // per-mixer
1491
Mixer.Info[] allInfos; // for all mixers
1492
1493
for(int i = 0; i < providers.size(); i++ ) {
1494
someInfos = providers.get(i).getMixerInfo();
1495
1496
for (int j = 0; j < someInfos.length; j++) {
1497
infos.add(someInfos[j]);
1498
}
1499
}
1500
1501
return infos;
1502
}
1503
1504
/**
1505
* Obtains the set of services currently installed on the system using the
1506
* SPI mechanism in 1.3.
1507
*
1508
* @param providerClass The type of providers requested. This should be one
1509
* of AudioFileReader.class, AudioFileWriter.class,
1510
* FormatConversionProvider.class, MixerProvider.class,
1511
* MidiDeviceProvider.class, MidiFileReader.class,
1512
* MidiFileWriter.class or SoundbankReader.class.
1513
* @return a List of instances of providers for the requested service. If no
1514
* providers are available, a vector of length 0 will be returned.
1515
*/
1516
private static List<?> getProviders(Class<?> providerClass) {
1517
return JDK13Services.getProviders(providerClass);
1518
}
1519
}
1520
1521