1/*
2 * Copyright (c) 2002, 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.LineEvent;
28import javax.sound.sampled.LineListener;
29import javax.sound.sampled.LineUnavailableException;
30import javax.sound.sampled.Mixer;
31import javax.sound.sampled.SourceDataLine;
32
33/**
34 * @test
35 * @bug 4498848
36 * @summary Sound causes crashes on Linux (part 2)
37 */
38public class SDLLinuxCrash implements Runnable {
39    SourceDataLine sdl;
40    int size;
41
42    SDLLinuxCrash(SourceDataLine sdl, int size) {
43        this.sdl = sdl;
44        this.size = size - (size % 4);
45    }
46
47    public void run() {
48        int written=0;
49        //byte[] buffer = new byte[4096];
50        byte[] buffer = data;
51        out("    starting data line feed thread.");
52        try {
53            while (written<size) {
54                int toWrite = buffer.length;
55                if (toWrite+written > size) {
56                    toWrite = size-written;
57                }
58                toWrite -= (toWrite % 4);
59                //out("    writing "+toWrite+" bytes.");
60                int thisWritten = sdl.write(buffer, 0, toWrite);
61                if (thisWritten<toWrite) {
62                    out("    only wrote "+thisWritten+" bytes instead of "+toWrite);
63                }
64                if (thisWritten<=0) {
65                    break;
66                }
67                written += thisWritten;
68            }
69        } catch (Throwable t) {
70            t.printStackTrace();
71        }
72        out("    leaving data line feed thread.");
73    }
74
75    public static long bytes2Ms(long bytes, AudioFormat format) {
76        return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize());
77    }
78
79    static int staticLen=1000;
80    static boolean addLen=true;
81
82    public static SourceDataLine start() throws Exception {
83        AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
84        if (addLen) {
85            staticLen+=(int) (staticLen/5)+1000;
86        } else {
87            staticLen-=(int) (staticLen/5)+1000;
88        }
89        if (staticLen>8*44100*4) {
90            staticLen = 8*44100*4;
91            addLen=!addLen;
92        }
93        if (staticLen<1000) {
94            staticLen = 1000;
95            addLen=!addLen;
96        }
97        int len = staticLen;
98        len -= (len % 4);
99        out("    preparing to play back "+len+" bytes == "+bytes2Ms(len, format)+"ms audio...");
100
101        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
102        SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(info);
103        sdl.addLineListener(new LineListener() {
104                public void update(LineEvent e) {
105                    if (e.getType() == LineEvent.Type.STOP) {
106                        out("    calling close() from event dispatcher thread");
107                        ((SourceDataLine) e.getSource()).close();
108                    }
109                    else if (e.getType() == LineEvent.Type.CLOSE) {
110                    }
111                }
112            });
113
114        out("    opening...");
115        sdl.open();
116        out("    starting...");
117        sdl.start();
118        (new Thread(new SDLLinuxCrash(sdl, len))).start();
119        return sdl;
120    }
121
122    public static void main(String[] args) throws Exception {
123        if (!isSoundcardInstalled()) {
124            return;
125        }
126
127        try {
128            int COUNT=10;
129            out();
130            out("4498848 Sound causes crashes on Linux (testing with SourceDataLine)");
131            if (args.length>0) {
132                COUNT=Integer.parseInt(args[0]);
133            }
134            for (int i=0; i<COUNT; i++) {
135                out("  trial "+(i+1)+"/"+COUNT);
136                SourceDataLine sdl = start();
137                int waitTime = 500+(1000*(i % 2)); // every 2nd time wait 1500, rather than 500ms.
138                out("    waiting for "+waitTime+" ms for audio playback to stop...");
139                Thread.sleep(waitTime);
140                out("    calling close() from main thread");
141                sdl.close();
142                // let the subsystem enough time to actually close the soundcard
143                out("    waiting for 2 seconds...");
144                Thread.sleep(2000);
145                out();
146            }
147            out("  waiting for 1 second...");
148            Thread.sleep(1000);
149        } catch (Exception e) {
150            e.printStackTrace();
151            out("  waiting for 1 second");
152            try {
153                Thread.sleep(1000);
154            } catch (InterruptedException ie) {}
155            // do not fail if no audio device installed - bug 4742021
156            if (!(e instanceof LineUnavailableException)) {
157                throw e;
158            }
159        }
160        out("Test passed");
161    }
162
163    static void out() {
164        out("");
165    }
166
167    static void out(String s) {
168        System.out.println(s); System.out.flush();
169    }
170
171    /**
172     * Returns true if at least one soundcard is correctly installed
173     * on the system.
174     */
175    public static boolean isSoundcardInstalled() {
176        boolean result = false;
177        try {
178            Mixer.Info[] mixers = AudioSystem.getMixerInfo();
179            if (mixers.length > 0) {
180                result = AudioSystem.getSourceDataLine(null) != null;
181            }
182        } catch (Exception e) {
183            System.err.println("Exception occured: "+e);
184        }
185        if (!result) {
186            System.err.println("Soundcard does not exist or sound drivers not installed!");
187            System.err.println("This test requires sound drivers for execution.");
188        }
189        return result;
190    }
191
192
193
194    static final byte[] data = new byte[] {
195        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
196        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
197        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
198        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
199        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
200        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
201        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
202        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
203        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
204        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
205        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
206        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
207        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
208        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
209        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
210        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
211        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
212        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
213        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
214        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
215        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
216        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
217        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
218        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
219        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
220        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
221        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
222        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
223        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
224        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
225        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
226        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
227        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
228        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
229        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
230        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
231        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
232        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
233        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
234        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
235        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
236        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
237        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
238        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
239        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
240        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
241        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
242        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
243        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
244        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
245        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
246        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
247        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
248        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
249        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
250        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
251        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
252        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
253        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
254        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
255        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
256        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
257        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
258        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
259        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
260        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
261        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
262        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
263        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
264        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
265        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
266        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
267        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
268        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
269        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
270        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
271        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
272        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
273        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
274        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
275        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
276        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
277        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
278        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
279        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
280        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
281        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
282        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
283        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
284        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
285        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
286        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
287        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
288        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
289        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
290        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
291        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
292        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
293        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
294        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
295        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
296        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
297        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
298        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
299        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
300        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
301        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
302        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
303        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
304        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
305        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
306        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
307        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
308        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
309        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
310        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120,
311        123, 110, 100, 60, 11, 10, 10, 10, 9, 9,
312        9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6,
313        7, 7, 7, 7, 8, 8, 8, 8, 9, 9,
314        9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, 122, 122
315    };
316
317}
318