1/*
2 * Copyright (c) 2003, 2016, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import javax.sound.sampled.AudioFormat;
25import javax.sound.sampled.AudioSystem;
26import javax.sound.sampled.DataLine;
27import javax.sound.sampled.LineUnavailableException;
28import javax.sound.sampled.Mixer;
29import javax.sound.sampled.TargetDataLine;
30
31/**
32 * @test
33 * @bug 4836433
34 * @summary Windows: TargetDataLine.flush() does not work. Since this test has
35 *          some real-time variance, I disabled it by making it a manual test.
36 * @run main/manual TargetDataLineFlush
37 */
38public class TargetDataLineFlush {
39    TargetDataLine inLine;
40    int SAMPLE_RATE = 11025;
41    int BUFFER_MILLIS = 1000;
42    int WAIT_MILLIS;
43    int BITS = 16;
44    int CHANNELS = 2;
45    int bufferSize;
46    AudioFormat format;
47    Mixer.Info[] mixers;
48    static boolean failed = false;
49
50    public TargetDataLineFlush() {
51        mixers = AudioSystem.getMixerInfo();
52    }
53
54    private void init() {
55        // float sampleRate, int sampleSizeInBits, int channels, boolean signed, boolean bigEndian
56        format = new AudioFormat( (float) SAMPLE_RATE, BITS, CHANNELS, true, false);
57        bufferSize = SAMPLE_RATE * BUFFER_MILLIS / 1000 * format.getFrameSize();
58    }
59
60    boolean openInputLine(int num)  throws LineUnavailableException {
61        init();
62        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
63        // Obtain and open a outLine.
64        if (num < 0) {
65            if (!AudioSystem.isLineSupported(info)) {
66                System.out.println("TargetDataLine is not supported by default mixer.");
67                return false;
68            }
69            inLine = (TargetDataLine) AudioSystem.getLine(info);
70        } else {
71            Mixer mixer = AudioSystem.getMixer(mixers[num]);
72            if (!mixer.isLineSupported(info)) {
73                System.out.println("TargetDataLine is not supported by this mixer.");
74                return false;
75            }
76            inLine = (TargetDataLine) mixer.getLine(info);
77        }
78        inLine.open(format, bufferSize);
79        /*if (Math.abs(inLine.getBufferSize() - bufferSize) > 100) {
80                inLine.close();
81                System.out.println("TargetDataLine does not support buffer size of "+bufferSize+" bytes!");
82                return false;
83        }*/
84        bufferSize = inLine.getBufferSize();
85        /* 3/4 of buffer size ot wait */
86        WAIT_MILLIS = (int) (bufferSize / format.getFrameSize() * 750 / format.getFrameRate());
87        System.out.println("Buffer size: "+bufferSize+" bytes = "
88            +((int) (bufferSize / format.getFrameSize() * 750 / format.getFrameRate()))+" millis");
89        return true;
90    }
91
92    private String available() {
93        int avail = inLine.available();
94        int availMillis = (int) (avail / format.getFrameSize() * 1000 / format.getFrameRate());
95        return "available "+avail+" bytes = "+availMillis+" millis";
96    }
97
98    private boolean recordSound(int num)  throws LineUnavailableException {
99        if (!openInputLine(num)) {
100            return false;
101        }
102        byte data[] = new byte[1000];
103        try {
104            System.out.println("Got line: "+inLine);
105            System.out.println("Start recording" );
106            inLine.start();
107            System.out.print("Warm-up...");
108            //System.out.print("Waiting 500 millis...");
109            try { Thread.sleep(500); } catch (InterruptedException ie) {}
110            //System.out.println("done. "+available());
111            //System.out.print("Reading all data...");
112            int avail0 = inLine.available();
113            if (avail0 == 0) {
114                System.out.println("Problem: TargetDataLine did not deliver any data!");
115                System.out.println("Not a test failure, but serious failure nonetheless.");
116            } else {
117                while ((avail0 -= inLine.read(data, 0, Math.min(data.length, avail0))) > 0);
118                System.out.println("done.  "+available());
119                System.out.print("Waiting "+(WAIT_MILLIS)+" millis...");
120                try { Thread.sleep(WAIT_MILLIS); } catch (InterruptedException ie) {}
121                int avail1 = inLine.available();
122                System.out.println("done. "+available());
123
124                System.out.print("Flushing...");
125                inLine.flush();
126                System.out.println("done.            "+available());
127                System.out.print("Waiting "+(WAIT_MILLIS)+" millis...");
128                try { Thread.sleep(WAIT_MILLIS); } catch (InterruptedException ie) {}
129                int avail2 = inLine.available();
130                System.out.println("done.  "+available());
131                if (avail2 > avail1) {
132                    failed = true;
133                    System.out.println("Failed: Flushing with native flush() should "
134                                       +"result in fewer bytes available.");
135                }
136                if (avail2 == 0) {
137                    failed = true;
138                    System.out.println("Failed: Recording after flush() did not work at all!");
139                }
140            }
141        } finally {
142            System.out.print("Closing line....");
143            inLine.close();
144            System.out.println("done");
145        }
146        return true;
147    }
148
149    public void runTests(int testRuns) {
150        if (mixers.length > 0) {
151            for (int num = -1; num < mixers.length; num++) {
152                try {
153                    if (num<0) {
154                        System.out.println("------Using default line...." );
155                    } else {
156                        System.out.println("------Using line "+num+" from mixer "+mixers[num]+"...");
157                    }
158                    for (int testRun = 0; testRun < testRuns; testRun++) {
159                        if (testRuns>1) {
160                            System.out.println("--Run "+(testRun+1)+"/"+testRuns+":");
161                        }
162                        if (!recordSound(num)) {
163                            break;
164                        }
165                    }
166                } catch (Exception ex) {
167                    System.out.println("Caught " + ex );
168                }
169                System.out.println("------------------------------------------------------");
170                if (failed) {
171                    break;
172                }
173            }
174        } else {
175            System.out.println("No mixers present. Cannot execute this test.");
176        }
177    }
178
179
180    public static void main(String[] args) throws Exception {
181        System.out.println("Test TargetDataLineFlush");
182        System.out.println("This verifies that TargetDataLine.flush() actually");
183        System.out.println("flushes the native buffers. This is done by");
184        System.out.println("comparing a manual flush (i.e. just discarding");
185        System.out.println("everything that is currently available in the TargetDataLine)");
186        System.out.println("to a flushed line");
187        TargetDataLineFlush app = new TargetDataLineFlush();
188        int testRuns = 1;
189        if (args.length > 0) {
190            try {
191                testRuns = Integer.parseInt(args[0]);
192            } catch (NumberFormatException nfe) {
193                System.out.println("Usage: java TargetDataLineFlush [number of runs]");
194                System.out.println("Parameters ignored.");
195            }
196        }
197        app.runTests(testRuns);
198        if (failed) {
199            throw new Exception("Test FAILED");
200        }
201        // test always passes if it gets here
202        System.out.println("Test PASSED");
203    }
204}
205