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 
  24 import javax.sound.sampled.AudioFormat;
  25 import javax.sound.sampled.AudioSystem;
  26 import javax.sound.sampled.DataLine;
  27 import javax.sound.sampled.LineEvent;
  28 import javax.sound.sampled.LineListener;
  29 import javax.sound.sampled.LineUnavailableException;
  30 import javax.sound.sampled.Mixer;
  31 import javax.sound.sampled.SourceDataLine;
  32 
  33 /**
  34  * @test
  35  * @bug 4498848
  36  * @summary Sound causes crashes on Linux (part 2)
  37  */
  38 public 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 }