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