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 java.io.ByteArrayInputStream; 25 26import javax.sound.sampled.AudioFormat; 27import javax.sound.sampled.AudioInputStream; 28import javax.sound.sampled.AudioSystem; 29import javax.sound.sampled.Clip; 30import javax.sound.sampled.DataLine; 31import javax.sound.sampled.LineUnavailableException; 32import javax.sound.sampled.Mixer; 33 34/** 35 * @test 36 * @bug 4946945 37 * @summary Crash in javasound while running TicTacToe demo applet tiger b26 38 */ 39public class ClipFlushCrash { 40 static int frameCount = 441000; // lets say 10 seconds 41 static AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false); 42 static ByteArrayInputStream bais = 43 new ByteArrayInputStream(new byte[frameCount * format.getFrameSize()]); 44 45 static int success = 0; 46 47 public static void run(Mixer m) { 48 Clip clip = null; 49 try { 50 if (m == null) { 51 out("Using default mixer"); 52 clip = (Clip) AudioSystem.getClip(); 53 } else { 54 out("Using mixer: "+m); 55 DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); 56 clip = (Clip) m.getLine(info); 57 } 58 out(" got clip: "+clip); 59 if (!clip.getClass().toString().contains("Direct")) { 60 out(" no direct audio clip -> do not test."); 61 return; 62 } 63 64 out(" open"); 65 bais.reset(); 66 clip.open(new AudioInputStream(bais, format, frameCount)); 67 68 AT at1 = new AT(clip, "flush thread", 123) { 69 public void doAction() throws Exception { 70 log("flush"); 71 clip.flush(); 72 } 73 }; 74 AT at2 = new AT(clip, "setFramePosition thread", 67) { 75 public void doAction() throws Exception { 76 int pos = (int) (Math.random() * clip.getFrameLength()); 77 log("setPosition to frame "+pos); 78 clip.setFramePosition(pos); 79 } 80 }; 81 AT at3 = new AT(clip, "start/stop thread", 300) { 82 public void doAction() throws Exception { 83 if (clip.isRunning()) { 84 log("stop"); 85 clip.stop(); 86 } else { 87 log("start"); 88 clip.setFramePosition(0); 89 clip.start(); 90 } 91 } 92 }; 93 AT at4 = new AT(clip, "open/close thread", 600) { 94 public synchronized void doAction() throws Exception { 95 log("close"); 96 clip.close(); 97 wait(50); 98 if (!terminated) { 99 log("open"); 100 bais.reset(); 101 clip.open(new AudioInputStream(bais, format, frameCount)); 102 } 103 } 104 }; 105 106 out(" clip.start"); 107 clip.start(); 108 out(" for 10 seconds, call start/stop, setFramePosition, and flush from other threads"); 109 at1.start(); 110 at2.start(); 111 at3.start(); 112 at4.start(); 113 try { 114 Thread.sleep(10000); 115 } catch (InterruptedException ie) {} 116 out(" finished."); 117 at1.terminate(); 118 at2.terminate(); 119 at3.terminate(); 120 at4.terminate(); 121 out(" clip.close()"); 122 clip.close(); 123 success++; 124 } catch (LineUnavailableException luae) { 125 // line not available, test not failed 126 System.err.println(luae); 127 } catch (IllegalArgumentException iae) { 128 // line not available, test not failed 129 System.err.println(iae); 130 } catch (Throwable t) { 131 t.printStackTrace(); 132 } 133 } 134 135 public static void main(String[] args) throws Exception { 136 if (isSoundcardInstalled()) { 137 bais.mark(0); 138 run(null); 139 Mixer.Info[] infos = AudioSystem.getMixerInfo(); 140 for (int i = 0; i<infos.length; i++) { 141 try { 142 Mixer m = AudioSystem.getMixer(infos[i]); 143 run(m); 144 } catch (Exception e) { 145 } 146 } 147 if (success > 0) { 148 out("No crash -> Test passed"); 149 } else { 150 System.err.println("Test could not execute: please install an audio device"); 151 } 152 } 153 } 154 155 /** 156 * Returns true if at least one soundcard is correctly installed 157 * on the system. 158 */ 159 public static boolean isSoundcardInstalled() { 160 boolean result = false; 161 try { 162 Mixer.Info[] mixers = AudioSystem.getMixerInfo(); 163 if (mixers.length > 0) { 164 result = AudioSystem.getSourceDataLine(null) != null; 165 } 166 } catch (Exception e) { 167 System.err.println("Exception occured: "+e); 168 } 169 if (!result) { 170 System.err.println("Soundcard does not exist or sound drivers not installed!"); 171 System.err.println("This test requires sound drivers for execution."); 172 } 173 return result; 174 } 175 176 public static void out(String s) { 177 /*long t = System.nanoTime() / 1000000l; 178 String ts = ""+(t % 1000); 179 while (ts.length() < 3) ts = "0"+ts; 180 System.out.println(""+(t/1000)+":"+ts+" "+s); 181 System.out.flush();*/ 182 System.out.println(s); 183 } 184 185 private abstract static class AT extends Thread { 186 protected boolean terminated = false; 187 protected Clip clip; 188 private int waitTime; 189 190 public AT(Clip clip, String name, int waitTime) { 191 super(name); 192 this.clip = clip; 193 this.waitTime = waitTime; 194 } 195 196 public abstract void doAction() throws Exception; 197 198 public void run() { 199 log("start"); 200 while (!terminated) { 201 try { 202 synchronized(this) { 203 wait(waitTime); 204 } 205 if (!terminated) { 206 doAction(); 207 } 208 } catch(Exception e) { 209 log("exception: "+e); 210 } 211 } 212 log("exit"); 213 } 214 215 public synchronized void terminate() { 216 log("terminate"); 217 terminated = true; 218 notifyAll(); 219 } 220 221 protected void log(String s) { 222 //out(" "+Thread.currentThread().getId()+" "+getName()+": "+s); 223 out(" "+getName()+": "+s); 224 } 225 } 226} 227