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 java.io.ByteArrayInputStream;
  25 import java.io.InputStream;
  26 
  27 import javax.sound.sampled.AudioFormat;
  28 import javax.sound.sampled.AudioInputStream;
  29 import javax.sound.sampled.AudioSystem;
  30 import javax.sound.sampled.Clip;
  31 import javax.sound.sampled.DataLine;
  32 import javax.sound.sampled.LineEvent;
  33 import javax.sound.sampled.LineListener;
  34 import javax.sound.sampled.LineUnavailableException;
  35 import javax.sound.sampled.Mixer;
  36 
  37 /**
  38  * @test
  39  * @bug 4498848
  40  * @summary Sound causes crashes on Linux (part 3)
  41  */
  42 public class ClipLinuxCrash2 implements LineListener{
  43     Clip clip;
  44     int stopOccured;
  45     static final Object lock = new Object();
  46 
  47     public static long bytes2Ms(long bytes, AudioFormat format) {
  48         return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize());
  49     }
  50 
  51     static int staticLen=1000;
  52     static boolean addLen=true;
  53 
  54     ClipLinuxCrash2() {
  55     }
  56 
  57     public void update(LineEvent e) {
  58         if (e.getType() == LineEvent.Type.STOP) {
  59             stopOccured++;
  60             out("  Test program: receives STOP event for clip="+clip.toString()+" no."+stopOccured);
  61             out("  Test program: Calling close() in event dispatcher thread");
  62             clip.close();
  63             synchronized (lock) {
  64                 lock.notifyAll();
  65             }
  66         }
  67         else if (e.getType() == LineEvent.Type.CLOSE) {
  68             out("  Test program: receives CLOSE event for "+clip.toString());
  69             synchronized (lock) {
  70                 lock.notifyAll();
  71             }
  72         }
  73         else if (e.getType() == LineEvent.Type.START) {
  74             out("  Test program: receives START event for "+clip.toString());
  75         }
  76         else if (e.getType() == LineEvent.Type.OPEN) {
  77             out("  Test program: receives OPEN event for "+clip.toString());
  78         }
  79     }
  80 
  81     public long start() throws Exception {
  82         AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
  83 
  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("  Test program: preparing to play back "+len+" bytes == "+bytes2Ms(len, format)+"ms audio...");
 100 
 101         byte[] fakedata=new byte[len];
 102         InputStream is = new ByteArrayInputStream(fakedata);
 103         AudioInputStream ais = new AudioInputStream(is, format, fakedata.length/format.getFrameSize());
 104 
 105         DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
 106         clip = (Clip) AudioSystem.getLine(info);
 107         clip.addLineListener(this);
 108 
 109         out("  Test program: opening clip="+((clip==null)?"null":clip.toString()));
 110         clip.open(ais);
 111         ais.close();
 112         out("  Test program: starting clip="+((clip==null)?"null":clip.toString()));
 113         clip.start();
 114         return bytes2Ms(fakedata.length, format);
 115     }
 116 
 117     public static void main(String[] args) throws Exception {
 118         if (!isSoundcardInstalled()) {
 119             return;
 120         }
 121 
 122         try {
 123             int COUNT=10;
 124             out();
 125             out("4498848 Sound causes crashes on Linux");
 126             if (args.length>0) {
 127                 COUNT=Integer.parseInt(args[0]);
 128             }
 129             for (int i=0; i<COUNT; i++) {
 130                 out("trial "+(i+1)+"/"+COUNT);
 131                 ClipLinuxCrash2 t = new ClipLinuxCrash2();
 132                 t.start();
 133                 int waitTime = 300+(1300*(i % 2)); // every 2nd time wait 1600, rather than 300ms.
 134                 out("  Test program: waiting for "+waitTime+" ms for audio playback to stop...");
 135                 Thread.sleep(waitTime);
 136                 out("  Test program: calling close() from main thread");
 137                 t.clip.close();
 138                 // let the subsystem enough time to actually close the soundcard
 139                 //out("  Test program: waiting for 2 seconds...");
 140                 //Thread.sleep(2000);
 141                 //out();
 142             }
 143             out("  Test program: waiting for 1 second...");
 144             Thread.sleep(1000);
 145         } catch (Exception e) {
 146             e.printStackTrace();
 147             out("  Test program: waiting for 1 second");
 148             try {
 149                 Thread.sleep(1000);
 150             } catch (InterruptedException ie) {}
 151             // do not fail if no audio device installed - bug 4742021
 152             if (!(e instanceof LineUnavailableException)) {
 153                 throw e;
 154             }
 155         }
 156         out("Test passed");
 157     }
 158 
 159     static void out() {
 160         out("");
 161     }
 162 
 163     static void out(String s) {
 164         System.out.println(s); System.out.flush();
 165     }
 166 
 167     /**
 168      * Returns true if at least one soundcard is correctly installed
 169      * on the system.
 170      */
 171     public static boolean isSoundcardInstalled() {
 172         boolean result = false;
 173         try {
 174             Mixer.Info[] mixers = AudioSystem.getMixerInfo();
 175             if (mixers.length > 0) {
 176                 result = AudioSystem.getSourceDataLine(null) != null;
 177             }
 178         } catch (Exception e) {
 179             System.err.println("Exception occured: "+e);
 180         }
 181         if (!result) {
 182             System.err.println("Soundcard does not exist or sound drivers not installed!");
 183             System.err.println("This test requires sound drivers for execution.");
 184         }
 185         return result;
 186     }
 187 
 188 }